🛂(frontend) bind ai_proxy abilities with AI feature

Bind ai_proxy abilities to the AI feature.
If ai_proxy is false, the AI feature will
not be available.
This commit is contained in:
Anthony LC
2025-06-10 16:16:01 +02:00
parent 5c8fff01a5
commit e1e0e5ebd8
5 changed files with 71 additions and 19 deletions

View File

@@ -696,6 +696,53 @@ test.describe('Doc Editor', () => {
});
});
test(`it checks ai_proxy ability`, async ({ page, browserName }) => {
await mockedDocument(page, {
accesses: [
{
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
role: 'owner',
user: {
email: 'super@owner.com',
full_name: 'Super Owner',
},
},
],
abilities: {
destroy: true, // Means owner
link_configuration: true,
ai_proxy: false,
accesses_manage: true,
accesses_view: true,
update: true,
partial_update: true,
retrieve: true,
},
link_reach: 'restricted',
link_role: 'editor',
created_at: '2021-09-01T09:00:00Z',
title: '',
});
const [randomDoc] = await createDoc(
page,
'doc-editor-ai-proxy',
browserName,
1,
);
await verifyDocName(page, randomDoc);
await page.locator('.bn-block-outer').last().fill('Hello World');
const editor = page.locator('.ProseMirror');
await editor.getByText('Hello').selectText();
await expect(page.getByRole('button', { name: 'Ask AI' })).toBeHidden();
await page.locator('.bn-block-outer').last().fill('/');
await expect(page.getByText('Write with AI')).toBeHidden();
});
test('it downloads unsafe files', async ({ page, browserName }) => {
const [randomDoc] = await createDoc(page, 'doc-editor', browserName, 1);

View File

@@ -6,10 +6,14 @@ import { fetchAPI } from '@/api';
import { useConfig } from '@/core';
import { Doc } from '@/docs/doc-management';
export const useAI = (docId: Doc['id']) => {
export const useAI = (docId: Doc['id'], aiAllowed: boolean) => {
const conf = useConfig().data;
return useMemo(() => {
if (!aiAllowed) {
return null;
}
const extension = AIExtension({
transport: new DefaultChatTransport({
fetch: (input, init) => {
@@ -27,5 +31,5 @@ export const useAI = (docId: Doc['id']) => {
});
return extension;
}, [conf?.AI_BOT, docId]);
}, [conf?.AI_BOT, docId, aiAllowed]);
};

View File

@@ -20,6 +20,7 @@ import type { Awareness } from 'y-protocols/awareness';
import * as Y from 'yjs';
import { Box, TextErrors } from '@/components';
import { useConfig } from '@/core';
import { useCunninghamTheme } from '@/cunningham';
import { Doc, useProviderStore } from '@/docs/doc-management';
import { avatarUrlFromName, useAuth } from '@/features/auth';
@@ -46,7 +47,6 @@ import {
PdfBlock,
UploadLoaderBlock,
} from './custom-blocks';
const AIMenu = BlockNoteAI?.AIMenu;
const AIMenuController = BlockNoteAI?.AIMenuController;
const useAI = BlockNoteAI?.useAI;
@@ -104,7 +104,9 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
}
const { uploadFile, errorAttachment } = useUploadFile(doc.id);
const aiExtension = useAI?.(doc.id);
const conf = useConfig().data;
const aiAllowed = !!(conf?.AI_FEATURE_ENABLED && doc.abilities?.ai_proxy);
const aiExtension = useAI?.(doc.id, aiAllowed);
const collabName = user?.full_name || user?.email;
const cursorName = collabName || t('Anonymous');
@@ -266,11 +268,11 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
comments={showComments}
aria-label={t('Document editor')}
>
{aiExtension && AIMenuController && AIMenu && (
{aiAllowed && AIMenuController && AIMenu && (
<AIMenuController aiMenu={AIMenu} />
)}
<BlockNoteSuggestionMenu />
<BlockNoteToolbar />
<BlockNoteSuggestionMenu aiAllowed={aiAllowed} />
<BlockNoteToolbar aiAllowed={aiAllowed} />
</BlockNoteView>
</Box>
);
@@ -337,7 +339,7 @@ export const BlockNoteReader = ({
slashMenu={false}
comments={false}
>
<BlockNoteToolbar />
<BlockNoteToolbar aiAllowed={false} />
</BlockNoteView>
</Box>
);

View File

@@ -11,8 +11,6 @@ import {
import React, { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useConfig } from '@/core';
import {
DocsBlockSchema,
DocsInlineContentSchema,
@@ -32,7 +30,11 @@ const getMultiColumnSlashMenuItems =
const getAISlashMenuItems = BlockNoteAI?.getAISlashMenuItems;
export const BlockNoteSuggestionMenu = () => {
export const BlockNoteSuggestionMenu = ({
aiAllowed,
}: {
aiAllowed: boolean;
}) => {
const editor = useBlockNoteEditor<
DocsBlockSchema,
DocsInlineContentSchema,
@@ -44,7 +46,6 @@ export const BlockNoteSuggestionMenu = () => {
const fileBlocksName = dictionaryDate.slash_menu.file.group;
const getInterlinkingMenuItems = useGetInterlinkingMenuItems();
const { data: conf } = useConfig();
const getSlashMenuItems = useMemo(() => {
// We insert it after the "Code Block" item to have the interlinking block displayed after the basic blocks
@@ -56,9 +57,7 @@ export const BlockNoteSuggestionMenu = () => {
getMultiColumnSlashMenuItems?.(editor) || [],
getPdfReactSlashMenuItems(editor, t, fileBlocksName),
getCalloutReactSlashMenuItems(editor, t, basicBlocksName),
conf?.AI_FEATURE_ENABLED && getAISlashMenuItems
? getAISlashMenuItems(editor)
: [],
aiAllowed && getAISlashMenuItems ? getAISlashMenuItems(editor) : [],
);
const index = combinedMenu.findIndex(
@@ -80,7 +79,7 @@ export const BlockNoteSuggestionMenu = () => {
t,
fileBlocksName,
basicBlocksName,
conf?.AI_FEATURE_ENABLED,
aiAllowed,
getInterlinkingMenuItems,
]);

View File

@@ -21,7 +21,7 @@ import { ModalConfirmDownloadUnsafe } from './ModalConfirmDownloadUnsafe';
const AIToolbarButton = BlockNoteAI?.AIToolbarButton;
export const BlockNoteToolbar = () => {
export const BlockNoteToolbar = ({ aiAllowed }: { aiAllowed: boolean }) => {
const dict = useDictionary();
const [confirmOpen, setIsConfirmOpen] = useState(false);
const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>();
@@ -72,7 +72,7 @@ export const BlockNoteToolbar = () => {
const formattingToolbar = useCallback(() => {
return (
<FormattingToolbar>
{conf?.AI_FEATURE_ENABLED && AIToolbarButton && <AIToolbarButton />}
{aiAllowed && AIToolbarButton && <AIToolbarButton />}
<CommentToolbarButton />
@@ -87,7 +87,7 @@ export const BlockNoteToolbar = () => {
<MarkdownButton key="customButton" />
</FormattingToolbar>
);
}, [toolbarItems, conf?.AI_FEATURE_ENABLED]);
}, [toolbarItems, aiAllowed, conf?.AI_FEATURE_ENABLED]);
return (
<>