Skip to content

Commit 4bb64f2

Browse files
committed
🛂(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.
1 parent 8694359 commit 4bb64f2

File tree

5 files changed

+67
-22
lines changed

5 files changed

+67
-22
lines changed

src/frontend/apps/e2e/__tests__/app-impress/doc-editor.spec.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,53 @@ test.describe('Doc Editor', () => {
389389
await expect(page.getByText('Write with AI')).toBeVisible();
390390
});
391391

392+
test(`it checks ai_proxy ability`, async ({ page, browserName }) => {
393+
await mockedDocument(page, {
394+
accesses: [
395+
{
396+
id: 'b0df4343-c8bd-4c20-9ff6-fbf94fc94egg',
397+
role: 'owner',
398+
user: {
399+
400+
full_name: 'Super Owner',
401+
},
402+
},
403+
],
404+
abilities: {
405+
destroy: true, // Means owner
406+
link_configuration: true,
407+
ai_proxy: false,
408+
accesses_manage: true,
409+
accesses_view: true,
410+
update: true,
411+
partial_update: true,
412+
retrieve: true,
413+
},
414+
link_reach: 'restricted',
415+
link_role: 'editor',
416+
created_at: '2021-09-01T09:00:00Z',
417+
title: '',
418+
});
419+
420+
const [randomDoc] = await createDoc(
421+
page,
422+
'doc-editor-ai-proxy',
423+
browserName,
424+
1,
425+
);
426+
427+
await verifyDocName(page, randomDoc);
428+
429+
await page.locator('.bn-block-outer').last().fill('Hello World');
430+
431+
const editor = page.locator('.ProseMirror');
432+
await editor.getByText('Hello').selectText();
433+
434+
await expect(page.getByRole('button', { name: 'Ask AI' })).toBeHidden();
435+
await page.locator('.bn-block-outer').last().fill('/');
436+
await expect(page.getByText('Write with AI')).toBeHidden();
437+
});
438+
392439
test('it downloads unsafe files', async ({ page, browserName }) => {
393440
const [randomDoc] = await createDoc(page, 'doc-editor', browserName, 1);
394441

src/frontend/apps/impress/src/features/docs/doc-editor/components/AI/useAI.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ const userPrompts: Record<string, string> = {
4242
* This extends the default HTML promptBuilder from BlockNote to support custom prompt templates.
4343
* Custom prompts can be invoked using the pattern !promptName in the AI input field.
4444
*/
45-
export const useAI = (docId: Doc['id']) => {
45+
export const useAI = (doc: Doc) => {
4646
const conf = useConfig().data;
4747
const modules = useModuleAI();
48+
const aiAllowed = !!(conf?.AI_FEATURE_ENABLED && doc.abilities?.ai_proxy);
4849

4950
return useMemo(() => {
50-
if (!modules || !conf?.AI_MODEL) {
51+
if (!aiAllowed || !modules || !conf?.AI_MODEL) {
5152
return;
5253
}
5354

@@ -65,7 +66,7 @@ export const useAI = (docId: Doc['id']) => {
6566
const headers = new Headers(init?.headers);
6667
headers.delete('Authorization');
6768

68-
return fetchAPI(`documents/${docId}/ai-proxy/`, {
69+
return fetchAPI(`documents/${doc.id}/ai-proxy/`, {
6970
...init,
7071
headers,
7172
});
@@ -155,5 +156,5 @@ export const useAI = (docId: Doc['id']) => {
155156
});
156157

157158
return extension;
158-
}, [conf?.AI_BOT, conf?.AI_MODEL, docId, modules]);
159+
}, [aiAllowed, conf?.AI_BOT, conf?.AI_MODEL, doc.id, modules]);
159160
};

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteEditor.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,8 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
5757
const dictionary = useDictionary();
5858

5959
const { uploadFile, errorAttachment } = useUploadFile(doc.id);
60-
const aiExtension = useAI(doc.id);
60+
const aiExtension = useAI(doc);
61+
const aiAllowed = !!aiExtension;
6162

6263
const collabName = readOnly
6364
? 'Reader'
@@ -165,9 +166,9 @@ export const BlockNoteEditor = ({ doc, provider }: BlockNoteEditorProps) => {
165166
editable={!readOnly}
166167
theme="light"
167168
>
168-
{aiExtension && <AIMenuController aiMenu={AIMenu} />}
169-
<BlockNoteSuggestionMenu />
170-
<BlockNoteToolbar />
169+
{aiAllowed && <AIMenuController aiMenu={AIMenu} />}
170+
<BlockNoteSuggestionMenu aiAllowed={aiAllowed} />
171+
<BlockNoteToolbar aiAllowed={aiAllowed} />
171172
</BlockNoteView>
172173
</Box>
173174
);

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteSuggestionMenu.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import {
99
import React, { useMemo } from 'react';
1010
import { useTranslation } from 'react-i18next';
1111

12-
import { useConfig } from '@/core';
13-
1412
import { DocsBlockSchema } from '../types';
1513

1614
import { modGetAISlashMenuItems } from './AI';
@@ -19,11 +17,14 @@ import {
1917
getDividerReactSlashMenuItems,
2018
} from './custom-blocks';
2119

22-
export const BlockNoteSuggestionMenu = () => {
20+
export const BlockNoteSuggestionMenu = ({
21+
aiAllowed,
22+
}: {
23+
aiAllowed: boolean;
24+
}) => {
2325
const editor = useBlockNoteEditor<DocsBlockSchema>();
2426
const { t } = useTranslation();
2527
const basicBlocksName = useDictionary().slash_menu.page_break.group;
26-
const { data: conf } = useConfig();
2728

2829
const getSlashMenuItems = useMemo(() => {
2930
return async (query: string) => {
@@ -36,15 +37,13 @@ export const BlockNoteSuggestionMenu = () => {
3637
getPageBreakReactSlashMenuItems(editor),
3738
getCalloutReactSlashMenuItems(editor, t, basicBlocksName),
3839
getDividerReactSlashMenuItems(editor, t, basicBlocksName),
39-
conf?.AI_FEATURE_ENABLED && getAISlashMenuItems
40-
? getAISlashMenuItems(editor)
41-
: [],
40+
aiAllowed && getAISlashMenuItems ? getAISlashMenuItems(editor) : [],
4241
),
4342
query,
4443
),
4544
);
4645
};
47-
}, [basicBlocksName, editor, t, conf?.AI_FEATURE_ENABLED]);
46+
}, [basicBlocksName, editor, t, aiAllowed]);
4847

4948
return (
5049
<SuggestionMenuController

src/frontend/apps/impress/src/features/docs/doc-editor/components/BlockNoteToolBar/BlockNoteToolbar.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,21 +8,18 @@ import {
88
import React, { JSX, useCallback, useMemo, useState } from 'react';
99
import { useTranslation } from 'react-i18next';
1010

11-
import { useConfig } from '@/core/config/api';
12-
1311
import { AIToolbarButton } from '../AI';
1412
import { getCalloutFormattingToolbarItems } from '../custom-blocks';
1513

1614
import { FileDownloadButton } from './FileDownloadButton';
1715
import { MarkdownButton } from './MarkdownButton';
1816
import { ModalConfirmDownloadUnsafe } from './ModalConfirmDownloadUnsafe';
1917

20-
export const BlockNoteToolbar = () => {
18+
export const BlockNoteToolbar = ({ aiAllowed }: { aiAllowed: boolean }) => {
2119
const dict = useDictionary();
2220
const [confirmOpen, setIsConfirmOpen] = useState(false);
2321
const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>();
2422
const { t } = useTranslation();
25-
const { data: conf } = useConfig();
2623

2724
const toolbarItems = useMemo(() => {
2825
const toolbarItems = getFormattingToolbarItems([
@@ -56,15 +53,15 @@ export const BlockNoteToolbar = () => {
5653
const formattingToolbar = useCallback(() => {
5754
return (
5855
<FormattingToolbar>
59-
{conf?.AI_FEATURE_ENABLED && <AIToolbarButton />}
56+
{aiAllowed && <AIToolbarButton />}
6057

6158
{toolbarItems}
6259

6360
{/* Extra button to convert from markdown to json */}
6461
<MarkdownButton key="customButton" />
6562
</FormattingToolbar>
6663
);
67-
}, [toolbarItems, conf?.AI_FEATURE_ENABLED]);
64+
}, [toolbarItems, aiAllowed]);
6865

6966
return (
7067
<>

0 commit comments

Comments
 (0)