Browse Source
The bottom composer is the canonical image-generation control surface now. The legacy right-side control panel was still rendering schema defaults for selected image nodes, which made aspect and size controls disagree on the same operation. Constraint: Image generation controls must stay consistent with the Popi composer UX Rejected: Synchronize both panels | duplicating controls preserves the confusing two-source UI Confidence: high Scope-risk: narrow Directive: Do not re-enable the right-side image panel unless it reads from the same composer-owned state Tested: npm run test:run -- src/components/__tests__/ControlPanel.test.tsx Tested: npm run test:run -- src/components/__tests__/GenerationComposer.test.tsx src/components/__tests__/ControlPanel.test.tsx Tested: PROVIDER_MODE=popi NEXT_PUBLIC_PROVIDER_MODE=popi npm run build Tested: Playwright localhost check for composer visible and legacy image settings absentfeature/add_agent_md
2 changed files with 111 additions and 0 deletions
@ -0,0 +1,101 @@ |
|||
import { render, screen } from "@testing-library/react"; |
|||
import { beforeEach, describe, expect, it, vi } from "vitest"; |
|||
import { ControlPanel } from "@/components/nodes/ControlPanel"; |
|||
import { useWorkflowStore } from "@/store/workflowStore"; |
|||
import type { WorkflowNode } from "@/types"; |
|||
|
|||
vi.mock("@/hooks/useInlineParameters", () => ({ |
|||
useInlineParameters: () => ({ inlineParametersEnabled: false }), |
|||
})); |
|||
|
|||
vi.mock("@/components/nodes/ModelParameters", () => ({ |
|||
ModelParameters: () => <div data-testid="model-parameters" />, |
|||
})); |
|||
|
|||
vi.mock("@/components/modals/ModelSearchDialog", () => ({ |
|||
ModelSearchDialog: () => null, |
|||
})); |
|||
|
|||
function imageNode(): WorkflowNode { |
|||
return { |
|||
id: "image-1", |
|||
type: "nanoBanana", |
|||
selected: true, |
|||
position: { x: 0, y: 0 }, |
|||
data: { |
|||
inputImages: [], |
|||
inputPrompt: "coffee spilled", |
|||
outputImage: null, |
|||
aspectRatio: "16:9", |
|||
resolution: "1K", |
|||
model: "nano-banana-pro", |
|||
selectedModel: { |
|||
provider: "newapiwg", |
|||
modelId: "apiyi_nano_banana_2", |
|||
displayName: "apiyi_nano_banana_2", |
|||
capabilities: ["text-to-image", "image-to-image"], |
|||
}, |
|||
parameters: { quality: "auto", size: "1024x1024" }, |
|||
useGoogleSearch: false, |
|||
useImageSearch: false, |
|||
status: "idle", |
|||
error: null, |
|||
imageHistory: [], |
|||
selectedHistoryIndex: 0, |
|||
}, |
|||
} as WorkflowNode; |
|||
} |
|||
|
|||
function videoNode(): WorkflowNode { |
|||
return { |
|||
id: "video-1", |
|||
type: "generateVideo", |
|||
selected: true, |
|||
position: { x: 0, y: 0 }, |
|||
data: { |
|||
prompt: "camera pan", |
|||
inputImage: null, |
|||
outputVideo: null, |
|||
selectedModel: { |
|||
provider: "newapiwg", |
|||
modelId: "video-model", |
|||
displayName: "Video Model", |
|||
capabilities: ["text-to-video"], |
|||
}, |
|||
parameters: {}, |
|||
status: "idle", |
|||
error: null, |
|||
progress: 0, |
|||
}, |
|||
} as WorkflowNode; |
|||
} |
|||
|
|||
describe("ControlPanel", () => { |
|||
beforeEach(() => { |
|||
vi.clearAllMocks(); |
|||
useWorkflowStore.setState({ |
|||
nodes: [], |
|||
edges: [], |
|||
isRunning: false, |
|||
}); |
|||
}); |
|||
|
|||
it("does not render duplicate settings for image generation nodes controlled by the composer", () => { |
|||
useWorkflowStore.setState({ nodes: [imageNode()] }); |
|||
|
|||
const { container } = render(<ControlPanel />); |
|||
|
|||
expect(container).toBeEmptyDOMElement(); |
|||
expect(screen.queryByText("Generate Image Settings")).not.toBeInTheDocument(); |
|||
expect(screen.queryByText("1024x1024")).not.toBeInTheDocument(); |
|||
}); |
|||
|
|||
it("keeps the right-side panel for generation nodes not yet owned by the composer", () => { |
|||
useWorkflowStore.setState({ nodes: [videoNode()] }); |
|||
|
|||
render(<ControlPanel />); |
|||
|
|||
expect(screen.getByText("Generate Video Settings")).toBeInTheDocument(); |
|||
expect(screen.getByTestId("model-parameters")).toBeInTheDocument(); |
|||
}); |
|||
}); |
|||
Loading…
Reference in new issue