改为运行时控制画板 Agent 入口
新增前端运行时配置接口下发画板 Agent 开关 将画板 Agent 入口改为读取后端运行时配置 把开关变量改为 GENARRATIVE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR 补充前后端测试和生产环境变量文档
This commit is contained in:
@@ -41,7 +41,6 @@ type EditorAgentConversationSummary = Awaited<
|
||||
type EditorAgentConversationDetail = Awaited<
|
||||
ReturnType<EditorAgentGetConversation>
|
||||
>;
|
||||
const EDITOR_AGENT_SIDEBAR_ENV = 'VITE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR';
|
||||
|
||||
const listEditorAgentConversationsMock = vi.hoisted(() =>
|
||||
vi.fn<
|
||||
@@ -110,6 +109,7 @@ const loadOrCreateRecentEditorProjectMock = vi.hoisted(() => vi.fn());
|
||||
const renameEditorProjectMock = vi.hoisted(() => vi.fn());
|
||||
const saveEditorProjectLayoutMock = vi.hoisted(() => vi.fn());
|
||||
const getPlatformProfileDashboardMock = vi.hoisted(() => vi.fn());
|
||||
const loadFrontendRuntimeConfigMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('../../services/image-editor/editorProjectClient', async () => {
|
||||
const actual = await vi.importActual<
|
||||
@@ -140,6 +140,10 @@ vi.mock('../../services/platform-entry/platformProfileClient', () => ({
|
||||
getPlatformProfileDashboard: getPlatformProfileDashboardMock,
|
||||
}));
|
||||
|
||||
vi.mock('../../services/frontendRuntimeConfigService', () => ({
|
||||
loadFrontendRuntimeConfig: loadFrontendRuntimeConfigMock,
|
||||
}));
|
||||
|
||||
vi.mock('../../services/image-editor/editorAgentClient', () => ({
|
||||
createEditorAgentConversation: createEditorAgentConversationMock,
|
||||
deleteEditorAgentConversation: deleteEditorAgentConversationMock,
|
||||
@@ -214,7 +218,7 @@ function openMinimap() {
|
||||
}
|
||||
|
||||
async function ensureAgentConversationOpen() {
|
||||
const agentButton = screen.getByRole('button', { name: '画布 Agent' });
|
||||
const agentButton = await screen.findByRole('button', { name: '画布 Agent' });
|
||||
if (agentButton.getAttribute('aria-pressed') !== 'true') {
|
||||
fireEvent.click(agentButton);
|
||||
}
|
||||
@@ -222,7 +226,9 @@ async function ensureAgentConversationOpen() {
|
||||
}
|
||||
|
||||
function enableEditorAgentSidebarForTest() {
|
||||
vi.stubEnv(EDITOR_AGENT_SIDEBAR_ENV, 'true');
|
||||
loadFrontendRuntimeConfigMock.mockResolvedValue({
|
||||
imageEditorAgentSidebarEnabled: true,
|
||||
});
|
||||
}
|
||||
|
||||
describe('ImageCanvasEditorView', () => {
|
||||
@@ -246,7 +252,9 @@ describe('ImageCanvasEditorView', () => {
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.stubEnv(EDITOR_AGENT_SIDEBAR_ENV, 'false');
|
||||
loadFrontendRuntimeConfigMock.mockResolvedValue({
|
||||
imageEditorAgentSidebarEnabled: false,
|
||||
});
|
||||
listEditorAgentConversationsMock.mockResolvedValue([]);
|
||||
createEditorAgentConversationMock.mockResolvedValue({
|
||||
...createEditorAgentConversationSummary({
|
||||
@@ -277,7 +285,7 @@ describe('ImageCanvasEditorView', () => {
|
||||
deleteEditorAgentConversationMock.mockReset();
|
||||
streamEditorAgentMessageMock.mockReset();
|
||||
getPlatformProfileDashboardMock.mockReset();
|
||||
vi.unstubAllEnvs();
|
||||
loadFrontendRuntimeConfigMock.mockReset();
|
||||
});
|
||||
|
||||
it('loads the project from projectid query before falling back to recent project', async () => {
|
||||
@@ -1487,6 +1495,8 @@ describe('ImageCanvasEditorView', () => {
|
||||
enableEditorAgentSidebarForTest();
|
||||
render(<ImageCanvasEditorView />);
|
||||
|
||||
await screen.findByRole('button', { name: '画布 Agent' });
|
||||
|
||||
const assetSidebar = openAssetSidebar();
|
||||
expect(within(assetSidebar).getByText('素材')).toBeTruthy();
|
||||
|
||||
@@ -1507,7 +1517,7 @@ describe('ImageCanvasEditorView', () => {
|
||||
screen.getByRole('complementary', { name: '画布任务列表' }),
|
||||
).toBeTruthy();
|
||||
|
||||
fireEvent.click(screen.getByRole('button', { name: '画布 Agent' }));
|
||||
fireEvent.click(await screen.findByRole('button', { name: '画布 Agent' }));
|
||||
expect(
|
||||
screen.getByRole('complementary', { name: '图片资源栏' }),
|
||||
).toBeTruthy();
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
loadEditorProject,
|
||||
loadEditorGenerationPricing,
|
||||
} from '../../services/image-editor/editorProjectClient';
|
||||
import { loadFrontendRuntimeConfig } from '../../services/frontendRuntimeConfigService';
|
||||
import { shouldShowRechargeEntry } from '../../services/payment/paymentPlatform';
|
||||
import { getPlatformProfileDashboard } from '../../services/platform-entry/platformProfileClient';
|
||||
import { useAuthUi } from '../auth/AuthUiContext';
|
||||
@@ -117,12 +118,6 @@ type ImageCanvasEditorViewProps = {
|
||||
onProjectAccessLost?: () => void;
|
||||
};
|
||||
|
||||
function resolveEditorAgentSidebarEnabled(
|
||||
rawValue = import.meta.env.VITE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR,
|
||||
): boolean {
|
||||
return rawValue === 'true' || rawValue === '1';
|
||||
}
|
||||
|
||||
function isCanvasStartupTool(value: string | null): value is CanvasStartupTool {
|
||||
return CANVAS_STARTUP_TOOLS.includes(value as CanvasStartupTool);
|
||||
}
|
||||
@@ -327,6 +322,9 @@ export function ImageCanvasEditorView({
|
||||
const showRechargeEntry = shouldShowRechargeEntry();
|
||||
const currentEditorUserId = authUi?.user?.id ?? null;
|
||||
const [isToolbarGuideVisible, setIsToolbarGuideVisible] = useState(false);
|
||||
const [isAgentConversationEnabled, setIsAgentConversationEnabled] =
|
||||
useState(false);
|
||||
const [isAgentConversationOpen, setIsAgentConversationOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
@@ -345,6 +343,28 @@ export function ImageCanvasEditorView({
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
let isMounted = true;
|
||||
void loadFrontendRuntimeConfig()
|
||||
.then((config) => {
|
||||
if (!isMounted) {
|
||||
return;
|
||||
}
|
||||
const enabled = config.imageEditorAgentSidebarEnabled === true;
|
||||
setIsAgentConversationEnabled(enabled);
|
||||
setIsAgentConversationOpen(enabled);
|
||||
})
|
||||
.catch(() => {
|
||||
if (!isMounted) {
|
||||
return;
|
||||
}
|
||||
setIsAgentConversationEnabled(false);
|
||||
setIsAgentConversationOpen(false);
|
||||
});
|
||||
return () => {
|
||||
isMounted = false;
|
||||
};
|
||||
}, []);
|
||||
const selectedLayerIdsRef = useRef<string[]>([]);
|
||||
const setQuickEditPanelRef = useRef<
|
||||
Dispatch<SetStateAction<QuickEditPanelState | null>>
|
||||
@@ -1167,10 +1187,6 @@ export function ImageCanvasEditorView({
|
||||
applyProjectSnapshot: applyGeneratedProjectSnapshot,
|
||||
onWalletBalanceMayHaveChanged: refreshEditorWalletBalance,
|
||||
});
|
||||
const isAgentConversationEnabled = resolveEditorAgentSidebarEnabled();
|
||||
const [isAgentConversationOpen, setIsAgentConversationOpen] = useState(
|
||||
() => isAgentConversationEnabled,
|
||||
);
|
||||
const effectiveIsAgentConversationOpen =
|
||||
isAgentConversationEnabled && isAgentConversationOpen;
|
||||
const toggleAgentConversation = useCallback(() => {
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const apiClientMocks = vi.hoisted(() => ({
|
||||
requestJson: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('./apiClient', async () => {
|
||||
const actual =
|
||||
await vi.importActual<typeof import('./apiClient')>('./apiClient');
|
||||
return {
|
||||
...actual,
|
||||
requestJson: apiClientMocks.requestJson,
|
||||
};
|
||||
});
|
||||
|
||||
import { loadFrontendRuntimeConfig } from './frontendRuntimeConfigService';
|
||||
|
||||
describe('frontendRuntimeConfigService', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
apiClientMocks.requestJson.mockResolvedValue({
|
||||
imageEditorAgentSidebarEnabled: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('loads public frontend runtime config without auth side effects', async () => {
|
||||
await expect(loadFrontendRuntimeConfig()).resolves.toEqual({
|
||||
imageEditorAgentSidebarEnabled: false,
|
||||
});
|
||||
|
||||
expect(apiClientMocks.requestJson).toHaveBeenCalledWith(
|
||||
'/api/runtime/frontend-config',
|
||||
{ method: 'GET' },
|
||||
'读取前端运行时配置失败',
|
||||
{
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
notifyAuthStateChange: false,
|
||||
clearAuthOnUnauthorized: false,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,21 @@
|
||||
import { requestJson } from './apiClient';
|
||||
|
||||
const FRONTEND_RUNTIME_CONFIG_API = '/api/runtime/frontend-config';
|
||||
|
||||
export type FrontendRuntimeConfig = {
|
||||
imageEditorAgentSidebarEnabled: boolean;
|
||||
};
|
||||
|
||||
export async function loadFrontendRuntimeConfig() {
|
||||
return requestJson<FrontendRuntimeConfig>(
|
||||
FRONTEND_RUNTIME_CONFIG_API,
|
||||
{ method: 'GET' },
|
||||
'读取前端运行时配置失败',
|
||||
{
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
notifyAuthStateChange: false,
|
||||
clearAuthOnUnauthorized: false,
|
||||
},
|
||||
);
|
||||
}
|
||||
Vendored
-1
@@ -2,7 +2,6 @@
|
||||
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_DEBUG_MODE?: string;
|
||||
readonly VITE_ENABLE_IMAGE_EDITOR_AGENT_SIDEBAR?: string;
|
||||
}
|
||||
|
||||
interface Window {
|
||||
|
||||
Reference in New Issue
Block a user