🐛(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>
This commit is contained in:
@@ -1684,6 +1684,7 @@ class ConfigView(drf.views.APIView):
|
||||
Return a dictionary of public settings.
|
||||
"""
|
||||
array_settings = [
|
||||
"AI_FEATURE_ENABLED",
|
||||
"COLLABORATION_WS_URL",
|
||||
"CRISP_WEBSITE_ID",
|
||||
"ENVIRONMENT",
|
||||
|
||||
@@ -49,4 +49,5 @@ def test_api_config(is_authenticated):
|
||||
"MEDIA_BASE_URL": "http://testserver/",
|
||||
"POSTHOG_KEY": {"id": "132456", "host": "https://eu.i.posthog-test.com"},
|
||||
"SENTRY_DSN": "https://sentry.test/123",
|
||||
"AI_FEATURE_ENABLED": False,
|
||||
}
|
||||
|
||||
@@ -528,6 +528,9 @@ class Base(Configuration):
|
||||
)
|
||||
|
||||
# AI service
|
||||
AI_FEATURE_ENABLED = values.BooleanValue(
|
||||
default=False, environ_name="AI_FEATURE_ENABLED", environ_prefix=None
|
||||
)
|
||||
AI_API_KEY = values.Value(None, environ_name="AI_API_KEY", environ_prefix=None)
|
||||
AI_BASE_URL = values.Value(None, environ_name="AI_BASE_URL", environ_prefix=None)
|
||||
AI_MODEL = values.Value(None, environ_name="AI_MODEL", environ_prefix=None)
|
||||
|
||||
@@ -5,6 +5,7 @@ import { expect, test } from '@playwright/test';
|
||||
import { createDoc, verifyDocName } from './common';
|
||||
|
||||
const config = {
|
||||
AI_FEATURE_ENABLED: true,
|
||||
CRISP_WEBSITE_ID: null,
|
||||
COLLABORATION_WS_URL: 'ws://localhost:4444/collaboration/ws/',
|
||||
ENVIRONMENT: 'development',
|
||||
@@ -117,6 +118,38 @@ test.describe('Config', () => {
|
||||
expect(webSocket.url()).toContain('ws://localhost:4444/collaboration/ws/');
|
||||
});
|
||||
|
||||
test('it checks the AI feature flag from config endpoint', async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await page.route('**/api/v1.0/config/', async (route) => {
|
||||
const request = route.request();
|
||||
if (request.method().includes('GET')) {
|
||||
await route.fulfill({
|
||||
json: {
|
||||
...config,
|
||||
AI_FEATURE_ENABLED: false,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
await route.continue();
|
||||
}
|
||||
});
|
||||
|
||||
await page.goto('/');
|
||||
|
||||
await createDoc(page, 'doc-ai-feature', browserName, 1);
|
||||
|
||||
await page.locator('.bn-block-outer').last().fill('Anything');
|
||||
await page.getByText('Anything').dblclick();
|
||||
expect(
|
||||
await page.locator('button[data-test="convertMarkdown"]').count(),
|
||||
).toBe(1);
|
||||
expect(await page.locator('button[data-test="ai-actions"]').count()).toBe(
|
||||
0,
|
||||
);
|
||||
});
|
||||
|
||||
test('it checks that Crisp is trying to init from config endpoint', async ({
|
||||
page,
|
||||
}) => {
|
||||
|
||||
@@ -338,6 +338,7 @@ test.describe('Doc Editor', () => {
|
||||
].forEach(({ ai_transform, ai_translate }) => {
|
||||
test(`it checks AI buttons when can transform is at "${ai_transform}" and can translate is at "${ai_translate}"`, async ({
|
||||
page,
|
||||
browserName,
|
||||
}) => {
|
||||
await mockedDocument(page, {
|
||||
accesses: [
|
||||
@@ -364,11 +365,17 @@ test.describe('Doc Editor', () => {
|
||||
link_reach: 'public',
|
||||
link_role: 'editor',
|
||||
created_at: '2021-09-01T09:00:00Z',
|
||||
title: '',
|
||||
});
|
||||
|
||||
await goToGridDoc(page);
|
||||
const [randomDoc] = await createDoc(
|
||||
page,
|
||||
'doc-editor-ai',
|
||||
browserName,
|
||||
1,
|
||||
);
|
||||
|
||||
await verifyDocName(page, 'Mocked document');
|
||||
await verifyDocName(page, randomDoc);
|
||||
|
||||
await page.locator('.bn-block-outer').last().fill('Hello World');
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ interface ConfigResponse {
|
||||
MEDIA_BASE_URL?: string;
|
||||
POSTHOG_KEY?: PostHogConf;
|
||||
SENTRY_DSN?: string;
|
||||
AI_FEATURE_ENABLED?: boolean;
|
||||
}
|
||||
|
||||
export const getConfig = async (): Promise<ConfigResponse> => {
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
import React, { JSX, useCallback, useMemo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { useConfig } from '@/core/config/api';
|
||||
|
||||
import { getQuoteFormattingToolbarItems } from '../custom-blocks';
|
||||
|
||||
import { AIGroupButton } from './AIButton';
|
||||
@@ -20,6 +22,7 @@ export const BlockNoteToolbar = () => {
|
||||
const [confirmOpen, setIsConfirmOpen] = useState(false);
|
||||
const [onConfirm, setOnConfirm] = useState<() => void | Promise<void>>();
|
||||
const { t } = useTranslation();
|
||||
const { data: conf } = useConfig();
|
||||
|
||||
const toolbarItems = useMemo(() => {
|
||||
const toolbarItems = getFormattingToolbarItems([
|
||||
@@ -56,13 +59,13 @@ export const BlockNoteToolbar = () => {
|
||||
{toolbarItems}
|
||||
|
||||
{/* Extra button to do some AI powered actions */}
|
||||
<AIGroupButton key="AIButton" />
|
||||
{conf?.AI_FEATURE_ENABLED && <AIGroupButton key="AIButton" />}
|
||||
|
||||
{/* Extra button to convert from markdown to json */}
|
||||
<MarkdownButton key="customButton" />
|
||||
</FormattingToolbar>
|
||||
);
|
||||
}, [toolbarItems]);
|
||||
}, [toolbarItems, conf?.AI_FEATURE_ENABLED]);
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user