mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-14 05:14:54 +00:00
feat(core): add split view to experimental features settings (#6093)
This commit is contained in:
@@ -5,11 +5,10 @@ import {
|
||||
import { Avatar } from '@affine/component/ui/avatar';
|
||||
import { Tooltip } from '@affine/component/ui/tooltip';
|
||||
import { useIsWorkspaceOwner } from '@affine/core/hooks/affine/use-is-workspace-owner';
|
||||
import { useIsEarlyAccess } from '@affine/core/hooks/affine/use-user-features';
|
||||
import { useWorkspaceBlobObjectUrl } from '@affine/core/hooks/use-workspace-blob';
|
||||
import { useWorkspaceAvailableFeatures } from '@affine/core/hooks/use-workspace-features';
|
||||
import { useWorkspaceInfo } from '@affine/core/hooks/use-workspace-info';
|
||||
import { UNTITLED_WORKSPACE_NAME } from '@affine/env/constant';
|
||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Logo1Icon } from '@blocksuite/icons';
|
||||
import {
|
||||
@@ -253,7 +252,7 @@ const WorkspaceListItem = ({
|
||||
const isCurrent = currentWorkspace.id === meta.id;
|
||||
const t = useAFFiNEI18N();
|
||||
const isOwner = useIsWorkspaceOwner(meta);
|
||||
const availableFeatures = useWorkspaceAvailableFeatures(meta);
|
||||
const isEarlyAccess = useIsEarlyAccess();
|
||||
|
||||
const onClickPreference = useCallback(() => {
|
||||
onClick('preference');
|
||||
@@ -263,11 +262,7 @@ const WorkspaceListItem = ({
|
||||
return subTabConfigs
|
||||
.filter(({ key }) => {
|
||||
if (key === 'experimental-features') {
|
||||
return (
|
||||
isOwner &&
|
||||
meta.flavour === WorkspaceFlavour.AFFINE_CLOUD &&
|
||||
availableFeatures.length > 0
|
||||
);
|
||||
return isOwner && isEarlyAccess;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
@@ -287,14 +282,7 @@ const WorkspaceListItem = ({
|
||||
</div>
|
||||
);
|
||||
});
|
||||
}, [
|
||||
activeSubTab,
|
||||
availableFeatures.length,
|
||||
isOwner,
|
||||
meta.flavour,
|
||||
onClick,
|
||||
t,
|
||||
]);
|
||||
}, [activeSubTab, isEarlyAccess, isOwner, onClick, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Button, Checkbox, Loading, Switch } from '@affine/component';
|
||||
import { SettingHeader } from '@affine/component/setting-components';
|
||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import {
|
||||
useSetWorkspaceFeature,
|
||||
@@ -79,6 +80,29 @@ interface ExperimentalFeaturesItemProps {
|
||||
}
|
||||
|
||||
const ExperimentalFeaturesItem = ({
|
||||
title,
|
||||
isMutating,
|
||||
checked,
|
||||
onChange,
|
||||
}: {
|
||||
title: React.ReactNode;
|
||||
isMutating?: boolean;
|
||||
checked: boolean;
|
||||
onChange: (checked: boolean) => void;
|
||||
}) => {
|
||||
return (
|
||||
<div className={styles.switchRow}>
|
||||
{title}
|
||||
<Switch
|
||||
checked={checked}
|
||||
onChange={onChange}
|
||||
className={isMutating ? styles.switchDisabled : ''}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const WorkspaceFeaturesSettingItem = ({
|
||||
feature,
|
||||
title,
|
||||
workspaceMetadata,
|
||||
@@ -96,14 +120,51 @@ const ExperimentalFeaturesItem = ({
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.switchRow}>
|
||||
{title}
|
||||
<Switch
|
||||
checked={localEnabled}
|
||||
onChange={onChange}
|
||||
className={isMutating ? styles.switchDisabled : ''}
|
||||
/>
|
||||
</div>
|
||||
<ExperimentalFeaturesItem
|
||||
title={title}
|
||||
isMutating={isMutating}
|
||||
checked={localEnabled}
|
||||
onChange={onChange}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const CopilotSettingRow = ({
|
||||
workspaceMetadata,
|
||||
}: {
|
||||
workspaceMetadata: WorkspaceMetadata;
|
||||
}) => {
|
||||
const features = useWorkspaceAvailableFeatures(workspaceMetadata);
|
||||
|
||||
return features.includes(FeatureType.Copilot) ? (
|
||||
<WorkspaceFeaturesSettingItem
|
||||
title="AI POC"
|
||||
workspaceMetadata={workspaceMetadata}
|
||||
feature={FeatureType.Copilot}
|
||||
/>
|
||||
) : null;
|
||||
};
|
||||
|
||||
const SplitViewSettingRow = () => {
|
||||
const { appSettings, updateSettings } = useAppSettingHelper();
|
||||
|
||||
const onToggle = useCallback(
|
||||
(checked: boolean) => {
|
||||
updateSettings('enableMultiView', checked);
|
||||
},
|
||||
[updateSettings]
|
||||
);
|
||||
|
||||
if (!environment.isDesktop) {
|
||||
return null; // only enable on desktop
|
||||
}
|
||||
|
||||
return (
|
||||
<ExperimentalFeaturesItem
|
||||
title="Split View"
|
||||
checked={appSettings.enableMultiView}
|
||||
onChange={onToggle}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -113,7 +174,6 @@ const ExperimentalFeaturesMain = ({
|
||||
workspaceMetadata: WorkspaceMetadata;
|
||||
}) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const features = useWorkspaceAvailableFeatures(workspaceMetadata);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -122,14 +182,8 @@ const ExperimentalFeaturesMain = ({
|
||||
'com.affine.settings.workspace.experimental-features.header.plugins'
|
||||
]()}
|
||||
/>
|
||||
|
||||
{features.includes(FeatureType.Copilot) ? (
|
||||
<ExperimentalFeaturesItem
|
||||
title="AI POC"
|
||||
workspaceMetadata={workspaceMetadata}
|
||||
feature={FeatureType.Copilot}
|
||||
/>
|
||||
) : null}
|
||||
<CopilotSettingRow workspaceMetadata={workspaceMetadata} />
|
||||
<SplitViewSettingRow />
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
24
packages/frontend/core/src/hooks/affine/use-user-features.ts
Normal file
24
packages/frontend/core/src/hooks/affine/use-user-features.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import { FeatureType, getUserFeaturesQuery } from '@affine/graphql';
|
||||
import type { BareFetcher, Middleware } from 'swr';
|
||||
|
||||
import { useQueryImmutable } from '../use-query';
|
||||
|
||||
const wrappedFetcher = (fetcher: BareFetcher<any> | null, ...args: any[]) =>
|
||||
fetcher?.(...args).catch(() => null);
|
||||
|
||||
const errorHandler: Middleware = useSWRNext => (key, fetcher, config) => {
|
||||
return useSWRNext(key, wrappedFetcher.bind(null, fetcher), config);
|
||||
};
|
||||
|
||||
export function useIsEarlyAccess() {
|
||||
const { data } = useQueryImmutable(
|
||||
{
|
||||
query: getUserFeaturesQuery,
|
||||
},
|
||||
{
|
||||
use: [errorHandler],
|
||||
}
|
||||
);
|
||||
|
||||
return data?.currentUser?.features.includes(FeatureType.EarlyAccess) ?? false;
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useAppSettingHelper } from '@affine/core/hooks/affine/use-app-setting-helper';
|
||||
import { useService } from '@toeverything/infra/di';
|
||||
import type { To } from 'history';
|
||||
import { useCallback } from 'react';
|
||||
@@ -13,12 +14,13 @@ export const WorkbenchLink = ({
|
||||
{ to: To } & React.HTMLProps<HTMLAnchorElement>
|
||||
>) => {
|
||||
const workbench = useService(Workbench);
|
||||
const { appSettings } = useAppSettingHelper();
|
||||
const handleClick = useCallback(
|
||||
(event: React.MouseEvent<HTMLAnchorElement>) => {
|
||||
event.preventDefault();
|
||||
// TODO: open this when multi view control is implemented
|
||||
if (
|
||||
(window as any).enableMultiView &&
|
||||
appSettings.enableMultiView &&
|
||||
environment.isDesktop &&
|
||||
(event.ctrlKey || event.metaKey)
|
||||
) {
|
||||
@@ -29,7 +31,7 @@ export const WorkbenchLink = ({
|
||||
|
||||
onClick?.(event);
|
||||
},
|
||||
[onClick, to, workbench]
|
||||
[appSettings.enableMultiView, onClick, to, workbench]
|
||||
);
|
||||
return (
|
||||
<a {...other} href="#" onClick={handleClick}>
|
||||
|
||||
Reference in New Issue
Block a user