mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-08-23 04:51:49 +08:00
fix(core): workspace feature should be workspace specific (#5677)
fix TOV-429
This commit is contained in:
+1
-1
@@ -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');
|
||||||
|
|||||||
+18
-6
@@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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
|
||||||
|
|||||||
+4
-4
@@ -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
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user