mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-04 08:38:34 +00:00
refactor(core): clear build config (#8268)
remove build config allowLocalWorkspace -> FeatureFlag enablePreloading -> removed enableNewSettingUnstableApi -> removed enableExperimentalFeature -> removed enableThemeEditor -> FeatureFlag remove some unused code
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
CHANGELOG_URL=
|
||||
ENABLE_PRELOADING=
|
||||
ENABLE_NEW_SETTING_UNSTABLE_API=
|
||||
ENABLE_CAPTCHA=
|
||||
CAPTCHA_SITE_KEY=
|
||||
|
||||
12
nx.json
12
nx.json
@@ -81,9 +81,6 @@
|
||||
"test": {
|
||||
"outputs": ["{workspaceRoot}/.nyc_output"],
|
||||
"inputs": [
|
||||
{
|
||||
"env": "ENABLE_PRELOADING"
|
||||
},
|
||||
{
|
||||
"env": "COVERAGE"
|
||||
}
|
||||
@@ -92,9 +89,6 @@
|
||||
"test:ui": {
|
||||
"outputs": ["{workspaceRoot}/.nyc_output"],
|
||||
"inputs": [
|
||||
{
|
||||
"env": "ENABLE_PRELOADING"
|
||||
},
|
||||
{
|
||||
"env": "COVERAGE"
|
||||
}
|
||||
@@ -102,11 +96,7 @@
|
||||
},
|
||||
"test:coverage": {
|
||||
"outputs": ["{workspaceRoot}/.nyc_output"],
|
||||
"inputs": [
|
||||
{
|
||||
"env": "ENABLE_PRELOADING"
|
||||
}
|
||||
]
|
||||
"inputs": []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
6
packages/common/env/src/global.ts
vendored
6
packages/common/env/src/global.ts
vendored
@@ -31,12 +31,6 @@ export type BUILD_CONFIG_TYPE = {
|
||||
imageProxyUrl: string;
|
||||
linkPreviewUrl: string;
|
||||
|
||||
allowLocalWorkspace: boolean;
|
||||
enablePreloading: boolean;
|
||||
enableNewSettingUnstableApi: boolean;
|
||||
enableExperimentalFeature: boolean;
|
||||
enableThemeEditor: boolean;
|
||||
|
||||
// TODO(@forehalo): remove
|
||||
isSelfHosted: boolean;
|
||||
};
|
||||
|
||||
@@ -8,20 +8,9 @@ setupGlobal();
|
||||
|
||||
const logger = new DebugLogger('affine:settings');
|
||||
|
||||
export type DateFormats =
|
||||
| 'MM/dd/YYYY'
|
||||
| 'dd/MM/YYYY'
|
||||
| 'YYYY-MM-dd'
|
||||
| 'YYYY.MM.dd'
|
||||
| 'YYYY/MM/dd'
|
||||
| 'dd-MMM-YYYY'
|
||||
| 'dd MMMM YYYY';
|
||||
|
||||
export type AppSetting = {
|
||||
clientBorder: boolean;
|
||||
windowFrameStyle: 'frameless' | 'NativeTitleBar';
|
||||
dateFormat: DateFormats;
|
||||
startWeekOnMonday: boolean;
|
||||
enableBlurBackground: boolean;
|
||||
enableNoisyBackground: boolean;
|
||||
autoCheckUpdate: boolean;
|
||||
@@ -33,21 +22,9 @@ export const windowFrameStyleOptions: AppSetting['windowFrameStyle'][] = [
|
||||
'NativeTitleBar',
|
||||
];
|
||||
|
||||
export const dateFormatOptions: DateFormats[] = [
|
||||
'MM/dd/YYYY',
|
||||
'dd/MM/YYYY',
|
||||
'YYYY-MM-dd',
|
||||
'YYYY.MM.dd',
|
||||
'YYYY/MM/dd',
|
||||
'dd-MMM-YYYY',
|
||||
'dd MMMM YYYY',
|
||||
];
|
||||
|
||||
const appSettingBaseAtom = atomWithStorage<AppSetting>('affine-settings', {
|
||||
clientBorder: BUILD_CONFIG.isElectron && !environment.isWindows,
|
||||
windowFrameStyle: 'frameless',
|
||||
dateFormat: dateFormatOptions[0],
|
||||
startWeekOnMonday: false,
|
||||
enableBlurBackground: true,
|
||||
enableNoisyBackground: true,
|
||||
autoCheckUpdate: true,
|
||||
|
||||
@@ -118,6 +118,20 @@ export const AFFINE_FLAGS = {
|
||||
configurable: isDesktopEnvironment,
|
||||
defaultState: false,
|
||||
},
|
||||
enable_theme_editor: {
|
||||
category: 'affine',
|
||||
displayName: 'Theme Editor',
|
||||
description: 'Enables theme editor.',
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: isCanaryBuild,
|
||||
},
|
||||
enable_local_workspace: {
|
||||
category: 'affine',
|
||||
displayName: 'Allow create local workspace',
|
||||
description: 'Allow create local workspace.',
|
||||
configurable: isCanaryBuild,
|
||||
defaultState: isDesktopEnvironment || isCanaryBuild,
|
||||
},
|
||||
} satisfies { [key in string]: FlagInfo };
|
||||
|
||||
export type AFFINE_FLAGS = typeof AFFINE_FLAGS;
|
||||
|
||||
@@ -1,77 +0,0 @@
|
||||
import { cssVar } from '@toeverything/theme';
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const header = style({
|
||||
position: 'relative',
|
||||
marginTop: '44px',
|
||||
});
|
||||
|
||||
export const subTitle = style({
|
||||
fontSize: cssVar('fontSm'),
|
||||
color: cssVar('textPrimaryColor'),
|
||||
fontWeight: 600,
|
||||
});
|
||||
|
||||
export const avatarWrapper = style({
|
||||
display: 'flex',
|
||||
margin: '10px 0',
|
||||
});
|
||||
|
||||
export const workspaceNameWrapper = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '8px',
|
||||
padding: '12px 0',
|
||||
});
|
||||
export const affineCloudWrapper = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: '6px',
|
||||
paddingTop: '10px',
|
||||
});
|
||||
|
||||
export const card = style({
|
||||
padding: '12px',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
borderRadius: '8px',
|
||||
backgroundColor: cssVar('backgroundSecondaryColor'),
|
||||
minHeight: '114px',
|
||||
position: 'relative',
|
||||
});
|
||||
|
||||
export const cardText = style({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
gap: '12px',
|
||||
});
|
||||
|
||||
export const cardTitle = style({
|
||||
fontSize: cssVar('fontBase'),
|
||||
color: cssVar('textPrimaryColor'),
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
});
|
||||
export const cardDescription = style({
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVar('textSecondaryColor'),
|
||||
maxWidth: '288px',
|
||||
});
|
||||
|
||||
export const cloudTips = style({
|
||||
fontSize: cssVar('fontXs'),
|
||||
color: cssVar('textSecondaryColor'),
|
||||
});
|
||||
|
||||
export const cloudSvgContainer = style({
|
||||
width: '146px',
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
position: 'absolute',
|
||||
bottom: '0',
|
||||
right: '0',
|
||||
pointerEvents: 'none',
|
||||
});
|
||||
@@ -1,290 +0,0 @@
|
||||
import { Avatar, Input, Switch, toast } from '@affine/component';
|
||||
import type { ConfirmModalProps } from '@affine/component/ui/modal';
|
||||
import { ConfirmModal, Modal } from '@affine/component/ui/modal';
|
||||
import { authAtom } from '@affine/core/components/atoms';
|
||||
import { useAsyncCallback } from '@affine/core/components/hooks/affine-async-hooks';
|
||||
import { DebugLogger } from '@affine/debug';
|
||||
import { apis } from '@affine/electron-api';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import {
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspacesService,
|
||||
} from '@toeverything/infra';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||
|
||||
import { buildShowcaseWorkspace } from '../../../bootstrap/first-app-data';
|
||||
import { AuthService } from '../../../modules/cloud';
|
||||
import { _addLocalWorkspace } from '../../../modules/workspace-engine';
|
||||
import { CloudSvg } from '../share-page-modal/cloud-svg';
|
||||
import * as styles from './index.css';
|
||||
|
||||
type CreateWorkspaceStep =
|
||||
| 'set-db-location'
|
||||
| 'name-workspace'
|
||||
| 'set-syncing-mode';
|
||||
|
||||
export type CreateWorkspaceMode = 'add' | 'new' | false;
|
||||
|
||||
const logger = new DebugLogger('CreateWorkspaceModal');
|
||||
|
||||
interface ModalProps {
|
||||
mode: CreateWorkspaceMode; // false means not open
|
||||
onClose: () => void;
|
||||
onCreate: (id: string, defaultDocId?: string) => void;
|
||||
}
|
||||
|
||||
interface NameWorkspaceContentProps extends ConfirmModalProps {
|
||||
loading: boolean;
|
||||
onConfirmName: (
|
||||
name: string,
|
||||
workspaceFlavour: WorkspaceFlavour,
|
||||
avatar?: File
|
||||
) => void;
|
||||
}
|
||||
|
||||
const shouldEnableCloud = !BUILD_CONFIG.allowLocalWorkspace;
|
||||
|
||||
const NameWorkspaceContent = ({
|
||||
loading,
|
||||
onConfirmName,
|
||||
...props
|
||||
}: NameWorkspaceContentProps) => {
|
||||
const t = useI18n();
|
||||
const [workspaceName, setWorkspaceName] = useState('');
|
||||
const [enable, setEnable] = useState(shouldEnableCloud);
|
||||
const session = useService(AuthService).session;
|
||||
const loginStatus = useLiveData(session.status$);
|
||||
|
||||
const setOpenSignIn = useSetAtom(authAtom);
|
||||
|
||||
const openSignInModal = useCallback(() => {
|
||||
setOpenSignIn(state => ({
|
||||
...state,
|
||||
openModal: true,
|
||||
}));
|
||||
}, [setOpenSignIn]);
|
||||
|
||||
const onSwitchChange = useCallback(
|
||||
(checked: boolean) => {
|
||||
if (loginStatus !== 'authenticated') {
|
||||
return openSignInModal();
|
||||
}
|
||||
return setEnable(checked);
|
||||
},
|
||||
[loginStatus, openSignInModal]
|
||||
);
|
||||
|
||||
const handleCreateWorkspace = useCallback(() => {
|
||||
onConfirmName(
|
||||
workspaceName,
|
||||
enable ? WorkspaceFlavour.AFFINE_CLOUD : WorkspaceFlavour.LOCAL
|
||||
);
|
||||
}, [enable, onConfirmName, workspaceName]);
|
||||
|
||||
const handleKeyDown = useCallback(
|
||||
(event: KeyboardEvent<HTMLInputElement>) => {
|
||||
if (event.key === 'Enter' && workspaceName) {
|
||||
handleCreateWorkspace();
|
||||
}
|
||||
},
|
||||
[handleCreateWorkspace, workspaceName]
|
||||
);
|
||||
|
||||
// Currently, when we create a new workspace and upload an avatar at the same time,
|
||||
// an error occurs after the creation is successful: get blob 404 not found
|
||||
return (
|
||||
<ConfirmModal
|
||||
defaultOpen={true}
|
||||
title={t['com.affine.nameWorkspace.title']()}
|
||||
description={t['com.affine.nameWorkspace.description']()}
|
||||
cancelText={t['com.affine.nameWorkspace.button.cancel']()}
|
||||
confirmText={t['com.affine.nameWorkspace.button.create']()}
|
||||
confirmButtonOptions={{
|
||||
variant: 'primary',
|
||||
loading,
|
||||
disabled: !workspaceName,
|
||||
['data-testid' as string]: 'create-workspace-create-button',
|
||||
}}
|
||||
closeButtonOptions={{
|
||||
['data-testid' as string]: 'create-workspace-close-button',
|
||||
}}
|
||||
onConfirm={handleCreateWorkspace}
|
||||
{...props}
|
||||
>
|
||||
<div className={styles.avatarWrapper}>
|
||||
<Avatar size={56} name={workspaceName} colorfulFallback />
|
||||
</div>
|
||||
|
||||
<div className={styles.workspaceNameWrapper}>
|
||||
<div className={styles.subTitle}>
|
||||
{t['com.affine.nameWorkspace.subtitle.workspace-name']()}
|
||||
</div>
|
||||
<Input
|
||||
autoFocus
|
||||
data-testid="create-workspace-input"
|
||||
onKeyDown={handleKeyDown}
|
||||
placeholder={t['com.affine.nameWorkspace.placeholder']()}
|
||||
maxLength={64}
|
||||
minLength={0}
|
||||
onChange={setWorkspaceName}
|
||||
size="large"
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.affineCloudWrapper}>
|
||||
<div className={styles.subTitle}>{t['AFFiNE Cloud']()}</div>
|
||||
<div className={styles.card}>
|
||||
<div className={styles.cardText}>
|
||||
<div className={styles.cardTitle}>
|
||||
<span>{t['com.affine.nameWorkspace.affine-cloud.title']()}</span>
|
||||
<Switch
|
||||
checked={enable}
|
||||
onChange={onSwitchChange}
|
||||
disabled={shouldEnableCloud}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.cardDescription}>
|
||||
{t['com.affine.nameWorkspace.affine-cloud.description']()}
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.cloudSvgContainer}>
|
||||
<CloudSvg />
|
||||
</div>
|
||||
</div>
|
||||
{shouldEnableCloud ? (
|
||||
<a
|
||||
className={styles.cloudTips}
|
||||
href={BUILD_CONFIG.downloadUrl}
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
>
|
||||
{t['com.affine.nameWorkspace.affine-cloud.web-tips']()}
|
||||
</a>
|
||||
) : null}
|
||||
</div>
|
||||
</ConfirmModal>
|
||||
);
|
||||
};
|
||||
|
||||
export const CreateWorkspaceModal = ({
|
||||
mode,
|
||||
onClose,
|
||||
onCreate,
|
||||
}: ModalProps) => {
|
||||
const [step, setStep] = useState<CreateWorkspaceStep>();
|
||||
const t = useI18n();
|
||||
const workspacesService = useService(WorkspacesService);
|
||||
const docsService = useService(DocsService);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// TODO(@Peng): maybe refactor using xstate?
|
||||
useLayoutEffect(() => {
|
||||
let canceled = false;
|
||||
// if mode changed, reset step
|
||||
if (mode === 'add') {
|
||||
// a hack for now
|
||||
// when adding a workspace, we will immediately let user select a db file
|
||||
// after it is done, it will effectively add a new workspace to app-data folder
|
||||
// so after that, we will be able to load it via importLocalWorkspace
|
||||
(async () => {
|
||||
if (!apis) {
|
||||
return;
|
||||
}
|
||||
logger.info('load db file');
|
||||
setStep(undefined);
|
||||
const result = await apis.dialog.loadDBFile();
|
||||
if (result.workspaceId && !canceled) {
|
||||
_addLocalWorkspace(result.workspaceId);
|
||||
workspacesService.list.revalidate();
|
||||
onCreate(result.workspaceId);
|
||||
} else if (result.error || result.canceled) {
|
||||
if (result.error) {
|
||||
toast(t[result.error]());
|
||||
}
|
||||
onClose();
|
||||
}
|
||||
})().catch(err => {
|
||||
console.error(err);
|
||||
});
|
||||
} else if (mode === 'new') {
|
||||
setStep('name-workspace');
|
||||
} else {
|
||||
setStep(undefined);
|
||||
}
|
||||
return () => {
|
||||
canceled = true;
|
||||
};
|
||||
}, [mode, onClose, onCreate, t, workspacesService]);
|
||||
|
||||
const onConfirmName = useAsyncCallback(
|
||||
async (name: string, workspaceFlavour: WorkspaceFlavour) => {
|
||||
track.$.$.$.createWorkspace({ flavour: workspaceFlavour });
|
||||
if (loading) return;
|
||||
setLoading(true);
|
||||
|
||||
// this will be the last step for web for now
|
||||
// fix me later
|
||||
if (BUILD_CONFIG.enablePreloading) {
|
||||
const { meta, defaultDocId } = await buildShowcaseWorkspace(
|
||||
workspacesService,
|
||||
workspaceFlavour,
|
||||
name
|
||||
);
|
||||
onCreate(meta.id, defaultDocId);
|
||||
} else {
|
||||
let defaultDocId: string | undefined = undefined;
|
||||
const { id } = await workspacesService.create(
|
||||
workspaceFlavour,
|
||||
async workspace => {
|
||||
workspace.meta.initialize();
|
||||
workspace.meta.setName(name);
|
||||
const page = docsService.createDoc();
|
||||
defaultDocId = page.id;
|
||||
}
|
||||
);
|
||||
onCreate(id, defaultDocId);
|
||||
}
|
||||
|
||||
setLoading(false);
|
||||
},
|
||||
[docsService, loading, onCreate, workspacesService]
|
||||
);
|
||||
|
||||
const onOpenChange = useCallback(
|
||||
(open: boolean) => {
|
||||
if (!open) {
|
||||
onClose();
|
||||
}
|
||||
},
|
||||
[onClose]
|
||||
);
|
||||
|
||||
if (step === 'name-workspace') {
|
||||
return (
|
||||
<NameWorkspaceContent
|
||||
loading={loading}
|
||||
open={mode !== false && !!step}
|
||||
onOpenChange={onOpenChange}
|
||||
onConfirmName={onConfirmName}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={mode !== false && !!step}
|
||||
width={560}
|
||||
onOpenChange={onOpenChange}
|
||||
contentOptions={{
|
||||
style: { padding: '10px' },
|
||||
}}
|
||||
>
|
||||
<div className={styles.header}></div>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -1,58 +0,0 @@
|
||||
import { Menu, MenuItem, MenuTrigger } from '@affine/component/ui/menu';
|
||||
import type { DateFormats } from '@toeverything/infra';
|
||||
import { dateFormatOptions } from '@toeverything/infra';
|
||||
import dayjs from 'dayjs';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useAppSettingHelper } from '../../../../../components/hooks/affine/use-app-setting-helper';
|
||||
|
||||
interface DateFormatMenuContentProps {
|
||||
currentOption: DateFormats;
|
||||
onSelect: (option: DateFormats) => void;
|
||||
}
|
||||
|
||||
const DateFormatMenuContent = ({
|
||||
onSelect,
|
||||
currentOption,
|
||||
}: DateFormatMenuContentProps) => {
|
||||
return (
|
||||
<>
|
||||
{dateFormatOptions.map(option => {
|
||||
return (
|
||||
<MenuItem
|
||||
key={option}
|
||||
selected={currentOption === option}
|
||||
onSelect={() => onSelect(option)}
|
||||
>
|
||||
{dayjs(new Date()).format(option)}
|
||||
</MenuItem>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const DateFormatSetting = () => {
|
||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
||||
const handleSelect = useCallback(
|
||||
(option: DateFormats) => {
|
||||
updateSettings('dateFormat', option);
|
||||
},
|
||||
[updateSettings]
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
items={
|
||||
<DateFormatMenuContent
|
||||
onSelect={handleSelect}
|
||||
currentOption={appSettings.dateFormat}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<MenuTrigger data-testid="date-format-menu-trigger" block>
|
||||
{dayjs(new Date()).format(appSettings.dateFormat)}
|
||||
</MenuTrigger>
|
||||
</Menu>
|
||||
);
|
||||
};
|
||||
@@ -6,15 +6,17 @@ import {
|
||||
SettingWrapper,
|
||||
} from '@affine/component/setting-components';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { AppSetting } from '@toeverything/infra';
|
||||
import { windowFrameStyleOptions } from '@toeverything/infra';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
useLiveData,
|
||||
useService,
|
||||
} from '@toeverything/infra';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { useAppSettingHelper } from '../../../../../components/hooks/affine/use-app-setting-helper';
|
||||
import { LanguageMenu } from '../../../language-menu';
|
||||
import { Page } from '../editor/page';
|
||||
import { DateFormatSetting } from './date-format-setting';
|
||||
import { settingWrapper } from './style.css';
|
||||
import { ThemeEditorSetting } from './theme-editor-setting';
|
||||
|
||||
@@ -62,6 +64,10 @@ export const ThemeSettings = () => {
|
||||
export const AppearanceSettings = () => {
|
||||
const t = useI18n();
|
||||
|
||||
const featureFlagService = useService(FeatureFlagService);
|
||||
const enableThemeEditor = useLiveData(
|
||||
featureFlagService.flags.enable_theme_editor.$
|
||||
);
|
||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
||||
|
||||
return (
|
||||
@@ -98,51 +104,10 @@ export const AppearanceSettings = () => {
|
||||
/>
|
||||
</SettingRow>
|
||||
) : null}
|
||||
{BUILD_CONFIG.enableNewSettingUnstableApi && BUILD_CONFIG.isElectron ? (
|
||||
<SettingRow
|
||||
name={t['com.affine.appearanceSettings.windowFrame.title']()}
|
||||
desc={t['com.affine.appearanceSettings.windowFrame.description']()}
|
||||
>
|
||||
<RadioGroup
|
||||
items={windowFrameStyleOptions.map(option => ({
|
||||
value: option,
|
||||
label:
|
||||
t[`com.affine.appearanceSettings.windowFrame.${option}`](),
|
||||
}))}
|
||||
value={appSettings.windowFrameStyle}
|
||||
className={settingWrapper}
|
||||
width={250}
|
||||
onChange={(value: AppSetting['windowFrameStyle']) => {
|
||||
updateSettings('windowFrameStyle', value);
|
||||
}}
|
||||
/>
|
||||
</SettingRow>
|
||||
) : null}
|
||||
{BUILD_CONFIG.enableThemeEditor ? <ThemeEditorSetting /> : null}
|
||||
{enableThemeEditor ? <ThemeEditorSetting /> : null}
|
||||
</SettingWrapper>
|
||||
{/* // TODO(@JimmFly): remove Page component when stable release */}
|
||||
<Page />
|
||||
{BUILD_CONFIG.enableNewSettingUnstableApi ? (
|
||||
<SettingWrapper title={t['com.affine.appearanceSettings.date.title']()}>
|
||||
<SettingRow
|
||||
name={t['com.affine.appearanceSettings.dateFormat.title']()}
|
||||
desc={t['com.affine.appearanceSettings.dateFormat.description']()}
|
||||
>
|
||||
<div className={settingWrapper}>
|
||||
<DateFormatSetting />
|
||||
</div>
|
||||
</SettingRow>
|
||||
<SettingRow
|
||||
name={t['com.affine.appearanceSettings.startWeek.title']()}
|
||||
desc={t['com.affine.appearanceSettings.startWeek.description']()}
|
||||
>
|
||||
<Switch
|
||||
checked={appSettings.startWeekOnMonday}
|
||||
onChange={checked => updateSettings('startWeekOnMonday', checked)}
|
||||
/>
|
||||
</SettingRow>
|
||||
</SettingWrapper>
|
||||
) : null}
|
||||
|
||||
{BUILD_CONFIG.isElectron ? (
|
||||
<SettingWrapper
|
||||
|
||||
@@ -107,14 +107,12 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
||||
}
|
||||
}
|
||||
|
||||
if (BUILD_CONFIG.enableExperimentalFeature) {
|
||||
settings.push({
|
||||
key: 'experimental-features',
|
||||
title: t['com.affine.settings.workspace.experimental-features'](),
|
||||
icon: ExperimentIcon,
|
||||
testId: 'experimental-features-trigger',
|
||||
});
|
||||
}
|
||||
settings.push({
|
||||
key: 'experimental-features',
|
||||
title: t['com.affine.settings.workspace.experimental-features'](),
|
||||
icon: ExperimentIcon,
|
||||
testId: 'experimental-features-trigger',
|
||||
});
|
||||
|
||||
return settings;
|
||||
};
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import { MenuItem } from '@affine/component/ui/menu';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { ImportIcon, PlusIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
useLiveData,
|
||||
useService,
|
||||
} from '@toeverything/infra';
|
||||
|
||||
import * as styles from './index.css';
|
||||
|
||||
@@ -12,6 +17,10 @@ export const AddWorkspace = ({
|
||||
onNewWorkspace?: () => void;
|
||||
}) => {
|
||||
const t = useI18n();
|
||||
const featureFlagService = useService(FeatureFlagService);
|
||||
const enableLocalWorkspace = useLiveData(
|
||||
featureFlagService.flags.enable_local_workspace.$
|
||||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -36,7 +45,7 @@ export const AddWorkspace = ({
|
||||
className={styles.ItemContainer}
|
||||
>
|
||||
<div className={styles.ItemText}>
|
||||
{BUILD_CONFIG.allowLocalWorkspace
|
||||
{enableLocalWorkspace
|
||||
? t['com.affine.workspaceList.addWorkspace.create']()
|
||||
: t['com.affine.workspaceList.addWorkspace.create-cloud']()}
|
||||
</div>
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import { Logo1Icon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
useLiveData,
|
||||
useService,
|
||||
type WorkspaceMetadata,
|
||||
@@ -75,6 +76,7 @@ const UserWithWorkspaceListInner = ({
|
||||
}: UserWithWorkspaceListProps) => {
|
||||
const createWorkspaceDialogService = useService(CreateWorkspaceDialogService);
|
||||
const session = useLiveData(useService(AuthService).session.session$);
|
||||
const featureFlagService = useService(FeatureFlagService);
|
||||
|
||||
const isAuthenticated = session.status === 'authenticated';
|
||||
|
||||
@@ -88,7 +90,10 @@ const UserWithWorkspaceListInner = ({
|
||||
}, [setOpenSignIn]);
|
||||
|
||||
const onNewWorkspace = useCallback(() => {
|
||||
if (!isAuthenticated && !BUILD_CONFIG.allowLocalWorkspace) {
|
||||
if (
|
||||
!isAuthenticated &&
|
||||
!featureFlagService.flags.enable_local_workspace.value
|
||||
) {
|
||||
return openSignInModal();
|
||||
}
|
||||
track.$.navigationPanel.workspaceList.createWorkspace();
|
||||
@@ -99,7 +104,8 @@ const UserWithWorkspaceListInner = ({
|
||||
});
|
||||
onEventEnd?.();
|
||||
}, [
|
||||
createWorkspaceDialogService.dialog,
|
||||
createWorkspaceDialogService,
|
||||
featureFlagService,
|
||||
isAuthenticated,
|
||||
onCreatedWorkspace,
|
||||
onEventEnd,
|
||||
|
||||
@@ -14,14 +14,14 @@ import {
|
||||
} from 'react';
|
||||
import { type LoaderFunction, useSearchParams } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
buildShowcaseWorkspace,
|
||||
createFirstAppData,
|
||||
} from '../../bootstrap/first-app-data';
|
||||
import { AppFallback } from '../../components/affine/app-container';
|
||||
import { useNavigateHelper } from '../../components/hooks/use-navigate-helper';
|
||||
import { WorkspaceNavigator } from '../../components/workspace-selector';
|
||||
import { AuthService } from '../../modules/cloud';
|
||||
import {
|
||||
buildShowcaseWorkspace,
|
||||
createFirstAppData,
|
||||
} from '../../utils/first-app-data';
|
||||
|
||||
export const loader: LoaderFunction = async () => {
|
||||
return null;
|
||||
|
||||
@@ -9,7 +9,7 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import {
|
||||
initEmptyPage,
|
||||
FeatureFlagService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspacesService,
|
||||
@@ -18,9 +18,9 @@ import { useSetAtom } from 'jotai';
|
||||
import type { KeyboardEvent } from 'react';
|
||||
import { useCallback, useLayoutEffect, useState } from 'react';
|
||||
|
||||
import { buildShowcaseWorkspace } from '../../../bootstrap/first-app-data';
|
||||
import { AuthService } from '../../../modules/cloud';
|
||||
import { _addLocalWorkspace } from '../../../modules/workspace-engine';
|
||||
import { buildShowcaseWorkspace } from '../../../utils/first-app-data';
|
||||
import { CreateWorkspaceDialogService } from '../services/dialog';
|
||||
import * as styles from './dialog.css';
|
||||
|
||||
@@ -35,8 +35,6 @@ interface NameWorkspaceContentProps extends ConfirmModalProps {
|
||||
) => void;
|
||||
}
|
||||
|
||||
const shouldEnableCloud = !BUILD_CONFIG.allowLocalWorkspace;
|
||||
|
||||
const NameWorkspaceContent = ({
|
||||
loading,
|
||||
onConfirmName,
|
||||
@@ -44,7 +42,11 @@ const NameWorkspaceContent = ({
|
||||
}: NameWorkspaceContentProps) => {
|
||||
const t = useI18n();
|
||||
const [workspaceName, setWorkspaceName] = useState('');
|
||||
const [enable, setEnable] = useState(shouldEnableCloud);
|
||||
const featureFlagService = useService(FeatureFlagService);
|
||||
const enableLocalWorkspace = useLiveData(
|
||||
featureFlagService.flags.enable_local_workspace.$
|
||||
);
|
||||
const [enable, setEnable] = useState(!enableLocalWorkspace);
|
||||
const session = useService(AuthService).session;
|
||||
const loginStatus = useLiveData(session.status$);
|
||||
|
||||
@@ -132,7 +134,7 @@ const NameWorkspaceContent = ({
|
||||
<Switch
|
||||
checked={enable}
|
||||
onChange={onSwitchChange}
|
||||
disabled={shouldEnableCloud}
|
||||
disabled={!enableLocalWorkspace}
|
||||
/>
|
||||
</div>
|
||||
<div className={styles.cardDescription}>
|
||||
@@ -143,7 +145,7 @@ const NameWorkspaceContent = ({
|
||||
<CloudSvg />
|
||||
</div>
|
||||
</div>
|
||||
{shouldEnableCloud ? (
|
||||
{!enableLocalWorkspace ? (
|
||||
<a
|
||||
className={styles.cloudTips}
|
||||
href={BUILD_CONFIG.downloadUrl}
|
||||
@@ -213,27 +215,12 @@ const CreateWorkspaceDialog = () => {
|
||||
|
||||
// this will be the last step for web for now
|
||||
// fix me later
|
||||
if (BUILD_CONFIG.enablePreloading) {
|
||||
const { meta, defaultDocId } = await buildShowcaseWorkspace(
|
||||
workspacesService,
|
||||
workspaceFlavour,
|
||||
name
|
||||
);
|
||||
createWorkspaceDialogService.dialog.callback({ meta, defaultDocId });
|
||||
} else {
|
||||
let defaultDocId: string | undefined = undefined;
|
||||
const meta = await workspacesService.create(
|
||||
workspaceFlavour,
|
||||
async workspace => {
|
||||
workspace.meta.initialize();
|
||||
workspace.meta.setName(name);
|
||||
const page = workspace.createDoc();
|
||||
defaultDocId = page.id;
|
||||
initEmptyPage(page);
|
||||
}
|
||||
);
|
||||
createWorkspaceDialogService.dialog.callback({ meta, defaultDocId });
|
||||
}
|
||||
const { meta, defaultDocId } = await buildShowcaseWorkspace(
|
||||
workspacesService,
|
||||
workspaceFlavour,
|
||||
name
|
||||
);
|
||||
createWorkspaceDialogService.dialog.callback({ meta, defaultDocId });
|
||||
|
||||
createWorkspaceDialogService.dialog.close();
|
||||
setLoading(false);
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { useService } from '@toeverything/infra';
|
||||
import {
|
||||
FeatureFlagService,
|
||||
useLiveData,
|
||||
useServices,
|
||||
} from '@toeverything/infra';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
@@ -7,16 +11,22 @@ import { ThemeEditorService } from '../services/theme-editor';
|
||||
let _provided = false;
|
||||
|
||||
export const useCustomTheme = (target: HTMLElement) => {
|
||||
const themeEditor = useService(ThemeEditorService);
|
||||
const { themeEditorService, featureFlagService } = useServices({
|
||||
ThemeEditorService,
|
||||
FeatureFlagService,
|
||||
});
|
||||
const enableThemeEditor = useLiveData(
|
||||
featureFlagService.flags.enable_theme_editor.$
|
||||
);
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
useEffect(() => {
|
||||
if (!BUILD_CONFIG.enableThemeEditor) return;
|
||||
if (!enableThemeEditor) return;
|
||||
if (_provided) return;
|
||||
|
||||
_provided = true;
|
||||
|
||||
const sub = themeEditor.customTheme$.subscribe(themeObj => {
|
||||
const sub = themeEditorService.customTheme$.subscribe(themeObj => {
|
||||
if (!themeObj) return;
|
||||
|
||||
const mode = resolvedTheme === 'dark' ? 'dark' : 'light';
|
||||
@@ -37,7 +47,7 @@ export const useCustomTheme = (target: HTMLElement) => {
|
||||
_provided = false;
|
||||
sub.unsubscribe();
|
||||
};
|
||||
}, [resolvedTheme, target.style, themeEditor.customTheme$]);
|
||||
}, [resolvedTheme, target.style, enableThemeEditor, themeEditorService]);
|
||||
};
|
||||
|
||||
export const CustomThemeModifier = () => {
|
||||
|
||||
@@ -4,7 +4,7 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import onboardingUrl from '@affine/templates/onboarding.zip';
|
||||
import { ZipTransformer } from '@blocksuite/blocks';
|
||||
import type { WorkspacesService } from '@toeverything/infra';
|
||||
import { DocsService, initEmptyPage } from '@toeverything/infra';
|
||||
import { DocsService } from '@toeverything/infra';
|
||||
|
||||
export async function buildShowcaseWorkspace(
|
||||
workspacesService: WorkspacesService,
|
||||
@@ -46,27 +46,11 @@ export async function createFirstAppData(workspacesService: WorkspacesService) {
|
||||
return;
|
||||
}
|
||||
localStorage.setItem('is-first-open', 'false');
|
||||
if (BUILD_CONFIG.enablePreloading) {
|
||||
const { meta, defaultDocId } = await buildShowcaseWorkspace(
|
||||
workspacesService,
|
||||
WorkspaceFlavour.LOCAL,
|
||||
DEFAULT_WORKSPACE_NAME
|
||||
);
|
||||
logger.info('create first workspace', defaultDocId);
|
||||
return { meta, defaultPageId: defaultDocId };
|
||||
} else {
|
||||
let defaultPageId: string | undefined = undefined;
|
||||
const workspaceMetadata = await workspacesService.create(
|
||||
WorkspaceFlavour.LOCAL,
|
||||
async workspace => {
|
||||
workspace.meta.initialize();
|
||||
workspace.meta.setName(DEFAULT_WORKSPACE_NAME);
|
||||
const page = workspace.createDoc();
|
||||
defaultPageId = page.id;
|
||||
initEmptyPage(page);
|
||||
}
|
||||
);
|
||||
logger.info('create first workspace', workspaceMetadata);
|
||||
return { meta: workspaceMetadata, defaultPageId };
|
||||
}
|
||||
const { meta, defaultDocId } = await buildShowcaseWorkspace(
|
||||
workspacesService,
|
||||
WorkspaceFlavour.LOCAL,
|
||||
DEFAULT_WORKSPACE_NAME
|
||||
);
|
||||
logger.info('create first workspace', defaultDocId);
|
||||
return { meta, defaultPageId: defaultDocId };
|
||||
}
|
||||
@@ -29,14 +29,6 @@ export function getBuildConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
|
||||
downloadUrl: 'https://affine.pro/download',
|
||||
imageProxyUrl: '/api/worker/image-proxy',
|
||||
linkPreviewUrl: '/api/worker/link-preview',
|
||||
enablePreloading: true,
|
||||
enableExperimentalFeature: true,
|
||||
allowLocalWorkspace:
|
||||
buildFlags.distribution === 'desktop' ? true : false,
|
||||
enableThemeEditor: false,
|
||||
|
||||
// CAUTION(@forehalo): product not ready, do not enable it
|
||||
enableNewSettingUnstableApi: false,
|
||||
};
|
||||
},
|
||||
get beta() {
|
||||
@@ -62,7 +54,6 @@ export function getBuildConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
|
||||
appBuildType: 'canary' as const,
|
||||
serverUrlPrefix: 'https://affine.fail',
|
||||
changelogUrl: 'https://github.com/toeverything/AFFiNE/releases',
|
||||
enableThemeEditor: true,
|
||||
};
|
||||
},
|
||||
};
|
||||
@@ -77,21 +68,6 @@ export function getBuildConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
|
||||
|
||||
const environmentPreset = {
|
||||
changelogUrl: process.env.CHANGELOG_URL ?? currentBuildPreset.changelogUrl,
|
||||
enablePreloading: process.env.ENABLE_PRELOADING
|
||||
? process.env.ENABLE_PRELOADING === 'true'
|
||||
: currentBuildPreset.enablePreloading,
|
||||
enableNewSettingUnstableApi: process.env.ENABLE_NEW_SETTING_UNSTABLE_API
|
||||
? process.env.ENABLE_NEW_SETTING_UNSTABLE_API === 'true'
|
||||
: currentBuildPreset.enableNewSettingUnstableApi,
|
||||
allowLocalWorkspace: process.env.ALLOW_LOCAL_WORKSPACE
|
||||
? process.env.ALLOW_LOCAL_WORKSPACE === 'true'
|
||||
: buildFlags.mode === 'development'
|
||||
? true
|
||||
: currentBuildPreset.allowLocalWorkspace,
|
||||
};
|
||||
|
||||
const testEnvironmentPreset = {
|
||||
allowLocalWorkspace: true,
|
||||
};
|
||||
|
||||
if (buildFlags.mode === 'development') {
|
||||
@@ -104,9 +80,5 @@ export function getBuildConfig(buildFlags: BuildFlags): BUILD_CONFIG_TYPE {
|
||||
// this environment variable is for debug proposes only
|
||||
// do not put them into CI
|
||||
...(process.env.CI ? {} : environmentPreset),
|
||||
|
||||
// test environment preset will overwrite current build preset
|
||||
// this environment variable is for github workflow e2e-test only
|
||||
...(process.env.IN_CI_TEST ? testEnvironmentPreset : {}),
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user