Skip to content

Commit f2ed8e0

Browse files
MatthiasAntoLC
authored andcommitted
🐛(frontend) conditionally render AI button in toolbar
Added a feature flag check to ensure the AIGroupButton is only rendered when AI_FEATURE_ENABLED is explicitly set to "true". This prevents the AI button from appearing when the feature is not configured or disabled. Fixes #782 Signed-off-by: Matthias <matthias@universum.com>
1 parent fbe8a26 commit f2ed8e0

File tree

9 files changed

+55
-4
lines changed

9 files changed

+55
-4
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ and this project adheres to
2525

2626
## Fixed
2727

28+
- 🐛(frontend) conditionally render AI button only when feature is enabled #814
2829
- 🐛(backend) compute ancestor_links in get_abilities if needed #725
2930
- 🔒️(back) restrict access to document accesses #801
3031

env.d/development/common.dist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ OIDC_REDIRECT_ALLOWED_HOSTS=["http://localhost:8083", "http://localhost:3000"]
5050
OIDC_AUTH_REQUEST_EXTRA_PARAMS={"acr_values": "eidas1"}
5151

5252
# AI
53+
AI_FEATURE_ENABLED=true
5354
AI_BASE_URL=https://openaiendpoint.com
5455
AI_API_KEY=password
5556
AI_MODEL=llama

src/backend/core/api/viewsets.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1684,6 +1684,7 @@ def get(self, request):
16841684
Return a dictionary of public settings.
16851685
"""
16861686
array_settings = [
1687+
"AI_FEATURE_ENABLED",
16871688
"COLLABORATION_WS_URL",
16881689
"CRISP_WEBSITE_ID",
16891690
"ENVIRONMENT",

src/backend/core/tests/test_api_config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ def test_api_config(is_authenticated):
4949
"MEDIA_BASE_URL": "http://testserver/",
5050
"POSTHOG_KEY": {"id": "132456", "host": "https://eu.i.posthog-test.com"},
5151
"SENTRY_DSN": "https://sentry.test/123",
52+
"AI_FEATURE_ENABLED": False,
5253
}

src/backend/impress/settings.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,6 +528,9 @@ class Base(Configuration):
528528
)
529529

530530
# AI service
531+
AI_FEATURE_ENABLED = values.BooleanValue(
532+
default=False, environ_name="AI_FEATURE_ENABLED", environ_prefix=None
533+
)
531534
AI_API_KEY = values.Value(None, environ_name="AI_API_KEY", environ_prefix=None)
532535
AI_BASE_URL = values.Value(None, environ_name="AI_BASE_URL", environ_prefix=None)
533536
AI_MODEL = values.Value(None, environ_name="AI_MODEL", environ_prefix=None)

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

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { expect, test } from '@playwright/test';
55
import { createDoc, verifyDocName } from './common';
66

77
const config = {
8+
AI_FEATURE_ENABLED: true,
89
CRISP_WEBSITE_ID: null,
910
COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/',
1011
ENVIRONMENT: 'development',
@@ -117,6 +118,38 @@ test.describe('Config', () => {
117118
expect(webSocket.url()).toContain('ws://localhost:4444/collaboration/ws/');
118119
});
119120

121+
test('it checks the AI feature flag from config endpoint', async ({
122+
page,
123+
browserName,
124+
}) => {
125+
await page.route('**/api/v1.0/config/', async (route) => {
126+
const request = route.request();
127+
if (request.method().includes('GET')) {
128+
await route.fulfill({
129+
json: {
130+
...config,
131+
AI_FEATURE_ENABLED: false,
132+
},
133+
});
134+
} else {
135+
await route.continue();
136+
}
137+
});
138+
139+
await page.goto('/');
140+
141+
await createDoc(page, 'doc-ai-feature', browserName, 1);
142+
143+
await page.locator('.bn-block-outer').last().fill('Anything');
144+
await page.getByText('Anything').dblclick();
145+
expect(
146+
await page.locator('button[data-test="convertMarkdown"]').count(),
147+
).toBe(1);
148+
expect(await page.locator('button[data-test="ai-actions"]').count()).toBe(
149+
0,
150+
);
151+
});
152+
120153
test('it checks that Crisp is trying to init from config endpoint', async ({
121154
page,
122155
}) => {

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

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,6 +338,7 @@ test.describe('Doc Editor', () => {
338338
].forEach(({ ai_transform, ai_translate }) => {
339339
test(`it checks AI buttons when can transform is at "${ai_transform}" and can translate is at "${ai_translate}"`, async ({
340340
page,
341+
browserName,
341342
}) => {
342343
await mockedDocument(page, {
343344
accesses: [
@@ -364,11 +365,17 @@ test.describe('Doc Editor', () => {
364365
link_reach: 'public',
365366
link_role: 'editor',
366367
created_at: '2021-09-01T09:00:00Z',
368+
title: '',
367369
});
368370

369-
await goToGridDoc(page);
371+
const [randomDoc] = await createDoc(
372+
page,
373+
'doc-editor-ai',
374+
browserName,
375+
1,
376+
);
370377

371-
await verifyDocName(page, 'Mocked document');
378+
await verifyDocName(page, randomDoc);
372379

373380
await page.locator('.bn-block-outer').last().fill('Hello World');
374381

src/frontend/apps/impress/src/core/config/api/useConfig.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ interface ConfigResponse {
1414
MEDIA_BASE_URL?: string;
1515
POSTHOG_KEY?: PostHogConf;
1616
SENTRY_DSN?: string;
17+
AI_FEATURE_ENABLED?: boolean;
1718
}
1819

1920
export const getConfig = async (): Promise<ConfigResponse> => {

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ 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+
1113
import { getQuoteFormattingToolbarItems } from '../custom-blocks';
1214

1315
import { AIGroupButton } from './AIButton';
@@ -20,6 +22,7 @@ export const BlockNoteToolbar = () => {
2022
const [confirmOpen, setIsConfirmOpen] = useState(false);
2123
const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>();
2224
const { t } = useTranslation();
25+
const { data: conf } = useConfig();
2326

2427
const toolbarItems = useMemo(() => {
2528
const toolbarItems = getFormattingToolbarItems([
@@ -56,13 +59,13 @@ export const BlockNoteToolbar = () => {
5659
{toolbarItems}
5760

5861
{/* Extra button to do some AI powered actions */}
59-
<AIGroupButton key="AIButton" />
62+
{conf?.AI_FEATURE_ENABLED && <AIGroupButton key="AIButton" />}
6063

6164
{/* Extra button to convert from markdown to json */}
6265
<MarkdownButton key="customButton" />
6366
</FormattingToolbar>
6467
);
65-
}, [toolbarItems]);
68+
}, [toolbarItems, conf?.AI_FEATURE_ENABLED]);
6669

6770
return (
6871
<>

0 commit comments

Comments
 (0)