fix(core): workspace feature should be workspace specific (#5677)

fix TOV-429
This commit is contained in:
Peng Xiao
2024-01-24 03:07:50 +00:00
parent 994ab96688
commit a687e7c0ed
7 changed files with 43 additions and 30 deletions
@@ -240,7 +240,7 @@ const WorkspaceListItem = ({
const isCurrent = currentWorkspace.id === meta.id; const isCurrent = currentWorkspace.id === meta.id;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const isOwner = useIsWorkspaceOwner(meta); const isOwner = useIsWorkspaceOwner(meta);
const availableFeatures = useWorkspaceAvailableFeatures(); const availableFeatures = useWorkspaceAvailableFeatures(meta);
const onClickPreference = useCallback(() => { const onClickPreference = useCallback(() => {
onClick('preference'); onClick('preference');
@@ -8,6 +8,7 @@ import {
} from '@affine/core/hooks/use-workspace-features'; } from '@affine/core/hooks/use-workspace-features';
import { FeatureType } from '@affine/graphql'; import { FeatureType } from '@affine/graphql';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type { WorkspaceMetadata } from '@affine/workspace/metadata';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import { atomWithStorage } from 'jotai/utils'; import { atomWithStorage } from 'jotai/utils';
import { Suspense, useCallback, useState } from 'react'; import { Suspense, useCallback, useState } from 'react';
@@ -74,16 +75,18 @@ const ExperimentalFeaturesPrompt = ({
interface ExperimentalFeaturesItemProps { interface ExperimentalFeaturesItemProps {
feature: FeatureType; feature: FeatureType;
title: React.ReactNode; title: React.ReactNode;
workspaceMetadata: WorkspaceMetadata;
} }
const ExperimentalFeaturesItem = ({ const ExperimentalFeaturesItem = ({
feature, feature,
title, title,
workspaceMetadata,
}: ExperimentalFeaturesItemProps) => { }: ExperimentalFeaturesItemProps) => {
const enabledFeatures = useWorkspaceEnabledFeatures(); const enabledFeatures = useWorkspaceEnabledFeatures(workspaceMetadata);
const enabled = enabledFeatures.includes(feature); const enabled = enabledFeatures.includes(feature);
const [localEnabled, setLocalEnabled] = useState(enabled); const [localEnabled, setLocalEnabled] = useState(enabled);
const { trigger, isMutating } = useSetWorkspaceFeature(); const { trigger, isMutating } = useSetWorkspaceFeature(workspaceMetadata);
const onChange = useCallback( const onChange = useCallback(
(checked: boolean) => { (checked: boolean) => {
setLocalEnabled(checked); setLocalEnabled(checked);
@@ -104,9 +107,13 @@ const ExperimentalFeaturesItem = ({
); );
}; };
const ExperimentalFeaturesMain = () => { const ExperimentalFeaturesMain = ({
workspaceMetadata,
}: {
workspaceMetadata: WorkspaceMetadata;
}) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const features = useWorkspaceAvailableFeatures(); const features = useWorkspaceAvailableFeatures(workspaceMetadata);
return ( return (
<> <>
@@ -119,6 +126,7 @@ const ExperimentalFeaturesMain = () => {
{features.includes(FeatureType.Copilot) ? ( {features.includes(FeatureType.Copilot) ? (
<ExperimentalFeaturesItem <ExperimentalFeaturesItem
title="AI POC" title="AI POC"
workspaceMetadata={workspaceMetadata}
feature={FeatureType.Copilot} feature={FeatureType.Copilot}
/> />
) : null} ) : null}
@@ -132,7 +140,11 @@ const experimentalFeaturesDisclaimerAtom = atomWithStorage(
false false
); );
export const ExperimentalFeatures = () => { export const ExperimentalFeatures = ({
workspaceMetadata,
}: {
workspaceMetadata: WorkspaceMetadata;
}) => {
const [enabled, setEnabled] = useAtom(experimentalFeaturesDisclaimerAtom); const [enabled, setEnabled] = useAtom(experimentalFeaturesDisclaimerAtom);
const handleConfirm = useAsyncCallback(async () => { const handleConfirm = useAsyncCallback(async () => {
setEnabled(true); setEnabled(true);
@@ -142,7 +154,7 @@ export const ExperimentalFeatures = () => {
} else { } else {
return ( return (
<Suspense fallback={<Loading />}> <Suspense fallback={<Loading />}>
<ExperimentalFeaturesMain /> <ExperimentalFeaturesMain workspaceMetadata={workspaceMetadata} />
</Suspense> </Suspense>
); );
} }
@@ -22,6 +22,6 @@ export const WorkspaceSetting = ({
/> />
); );
case 'experimental-features': case 'experimental-features':
return <ExperimentalFeatures />; return <ExperimentalFeatures workspaceMetadata={workspaceMetadata} />;
} }
}; };
@@ -5,25 +5,25 @@ import {
enabledFeaturesQuery, enabledFeaturesQuery,
setWorkspaceExperimentalFeatureMutation, setWorkspaceExperimentalFeatureMutation,
} from '@affine/graphql'; } from '@affine/graphql';
import { useAtomValue } from 'jotai'; import type { WorkspaceMetadata } from '@affine/workspace/metadata';
import { waitForCurrentWorkspaceAtom } from '../modules/workspace';
import { useAsyncCallback } from './affine-async-hooks'; import { useAsyncCallback } from './affine-async-hooks';
import { useMutateQueryResource, useMutation } from './use-mutation'; import { useMutateQueryResource, useMutation } from './use-mutation';
import { useQueryImmutable } from './use-query'; import { useQueryImmutable } from './use-query';
const emptyFeatures: FeatureType[] = []; const emptyFeatures: FeatureType[] = [];
export const useWorkspaceAvailableFeatures = () => { export const useWorkspaceAvailableFeatures = (
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); workspaceMetadata: WorkspaceMetadata
) => {
const isCloudWorkspace = const isCloudWorkspace =
currentWorkspace.flavour === WorkspaceFlavour.AFFINE_CLOUD; workspaceMetadata.flavour === WorkspaceFlavour.AFFINE_CLOUD;
const { data } = useQueryImmutable( const { data } = useQueryImmutable(
isCloudWorkspace isCloudWorkspace
? { ? {
query: availableFeaturesQuery, query: availableFeaturesQuery,
variables: { variables: {
id: currentWorkspace.id, id: workspaceMetadata.id,
}, },
} }
: undefined : undefined
@@ -31,16 +31,17 @@ export const useWorkspaceAvailableFeatures = () => {
return data?.workspace.availableFeatures ?? emptyFeatures; return data?.workspace.availableFeatures ?? emptyFeatures;
}; };
export const useWorkspaceEnabledFeatures = () => { export const useWorkspaceEnabledFeatures = (
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); workspaceMetadata: WorkspaceMetadata
) => {
const isCloudWorkspace = const isCloudWorkspace =
currentWorkspace.flavour === WorkspaceFlavour.AFFINE_CLOUD; workspaceMetadata.flavour === WorkspaceFlavour.AFFINE_CLOUD;
const { data } = useQueryImmutable( const { data } = useQueryImmutable(
isCloudWorkspace isCloudWorkspace
? { ? {
query: enabledFeaturesQuery, query: enabledFeaturesQuery,
variables: { variables: {
id: currentWorkspace.id, id: workspaceMetadata.id,
}, },
} }
: undefined : undefined
@@ -48,8 +49,9 @@ export const useWorkspaceEnabledFeatures = () => {
return data?.workspace.features ?? emptyFeatures; return data?.workspace.features ?? emptyFeatures;
}; };
export const useSetWorkspaceFeature = () => { export const useSetWorkspaceFeature = (
const currentWorkspace = useAtomValue(waitForCurrentWorkspaceAtom); workspaceMetadata: WorkspaceMetadata
) => {
const { trigger, isMutating } = useMutation({ const { trigger, isMutating } = useMutation({
mutation: setWorkspaceExperimentalFeatureMutation, mutation: setWorkspaceExperimentalFeatureMutation,
}); });
@@ -59,15 +61,15 @@ export const useSetWorkspaceFeature = () => {
trigger: useAsyncCallback( trigger: useAsyncCallback(
async (feature: FeatureType, enable: boolean) => { async (feature: FeatureType, enable: boolean) => {
await trigger({ await trigger({
workspaceId: currentWorkspace.id, workspaceId: workspaceMetadata.id,
feature, feature,
enable, enable,
}); });
await revalidate(enabledFeaturesQuery, vars => { await revalidate(enabledFeaturesQuery, vars => {
return vars.id === currentWorkspace.id; return vars.id === workspaceMetadata.id;
}); });
}, },
[currentWorkspace.id, revalidate, trigger] [workspaceMetadata.id, revalidate, trigger]
), ),
isMutating, isMutating,
}; };
@@ -11,7 +11,6 @@ import { JournalTodayButton } from '@affine/core/components/blocksuite/block-sui
import { PageHeaderMenuButton } from '@affine/core/components/blocksuite/block-suite-header/menu'; import { PageHeaderMenuButton } from '@affine/core/components/blocksuite/block-suite-header/menu';
import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch'; import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch';
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal'; import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
import type { BlockSuiteWorkspace } from '@affine/core/shared';
import type { Workspace } from '@affine/workspace'; import type { Workspace } from '@affine/workspace';
import { RightSidebarIcon } from '@blocksuite/icons'; import { RightSidebarIcon } from '@blocksuite/icons';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
@@ -189,7 +188,7 @@ export function DetailPageHeader(props: PageHeaderProps) {
} }
interface SidebarHeaderProps { interface SidebarHeaderProps {
workspace: BlockSuiteWorkspace; workspace: Workspace;
page: Page; page: Page;
} }
function WindowsSidebarHeader(props: SidebarHeaderProps) { function WindowsSidebarHeader(props: SidebarHeaderProps) {
@@ -206,7 +206,7 @@ const DetailPageImpl = memo(function DetailPageImpl({ page }: { page: Page }) {
sidebar={ sidebar={
!isInTrash ? ( !isInTrash ? (
<div className={styles.sidebarContainerInner}> <div className={styles.sidebarContainerInner}>
<RightSidebarHeader workspace={blockSuiteWorkspace} page={page} /> <RightSidebarHeader workspace={currentWorkspace} page={page} />
<EditorSidebar workspace={blockSuiteWorkspace} page={page} /> <EditorSidebar workspace={blockSuiteWorkspace} page={page} />
</div> </div>
) : null ) : null
@@ -1,8 +1,8 @@
import { IconButton } from '@affine/component'; import { IconButton } from '@affine/component';
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal'; import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
import { useWorkspaceEnabledFeatures } from '@affine/core/hooks/use-workspace-features'; import { useWorkspaceEnabledFeatures } from '@affine/core/hooks/use-workspace-features';
import type { BlockSuiteWorkspace } from '@affine/core/shared';
import { FeatureType } from '@affine/graphql'; import { FeatureType } from '@affine/graphql';
import type { Workspace } from '@affine/workspace/workspace';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import { assignInlineVars } from '@vanilla-extract/dynamic'; import { assignInlineVars } from '@vanilla-extract/dynamic';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
@@ -15,15 +15,15 @@ import {
import * as styles from './extensions.css'; import * as styles from './extensions.css';
export interface ExtensionTabsProps { export interface ExtensionTabsProps {
workspace: BlockSuiteWorkspace; workspace: Workspace;
page: Page; page: Page;
} }
// provide a switcher for active extensions // provide a switcher for active extensions
// will be used in global top header (MacOS) or sidebar (Windows) // will be used in global top header (MacOS) or sidebar (Windows)
export const ExtensionTabs = ({ page }: ExtensionTabsProps) => { export const ExtensionTabs = ({ page, workspace }: ExtensionTabsProps) => {
// todo: filter in editorExtensionsAtom instead? // todo: filter in editorExtensionsAtom instead?
const copilotEnabled = useWorkspaceEnabledFeatures().includes( const copilotEnabled = useWorkspaceEnabledFeatures(workspace.meta).includes(
FeatureType.Copilot FeatureType.Copilot
); );