FN-6165: fix builtin workflow prompt expansion
Keep builtin workflow prompts expandable while preserving read-only behavior. - move the builtin-disabled fieldset so the prompt expand control stays clickable - mark inline and fullscreen builtin prompt textareas read-only instead of disabling them - add coverage for desktop and mobile builtin prompt expansion behavior in WorkflowNodeEditor Files changed: .../app/components/WorkflowNodeEditor.tsx | 7 +++ .../__tests__/WorkflowNodeEditor.test.tsx | 61 ++++++++++++++++++++++ 2 files changed, 68 insertions(+) Fusion-Task-Id: FN-6165 Fusion-Task-Lineage: 02b1dd9f-6034-46a4-8790-75f1170ddb84
This commit is contained in:
@@ -2148,6 +2148,7 @@ function InnerEditor({
|
||||
<textarea
|
||||
rows={undefined}
|
||||
value={selectedNodePromptValue}
|
||||
readOnly={isBuiltin}
|
||||
onChange={(e) => updateSelectedData({ config: { prompt: e.target.value } })}
|
||||
autoFocus
|
||||
/>
|
||||
@@ -3176,6 +3177,7 @@ function InnerEditor({
|
||||
onChange={(e) => updateSelectedData({ label: e.target.value })}
|
||||
/>
|
||||
</label>
|
||||
</fieldset>
|
||||
|
||||
{selectedNode.data.kind === "prompt" || selectedNode.data.kind === "gate" ? (
|
||||
<div className="wf-prompt-editor">
|
||||
@@ -3184,9 +3186,13 @@ function InnerEditor({
|
||||
<textarea
|
||||
rows={5}
|
||||
value={selectedNodePromptValue}
|
||||
readOnly={isBuiltin}
|
||||
onChange={(e) => updateSelectedData({ config: { prompt: e.target.value } })}
|
||||
/>
|
||||
</label>
|
||||
{/* Expand button is outside <fieldset disabled={isBuiltin}> so it remains
|
||||
clickable for builtin workflows. Root cause: HTML spec disables all
|
||||
descendant buttons inside a disabled fieldset, including type="button". */}
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm wf-prompt-expand-btn wf-prompt-expand-btn--inline"
|
||||
@@ -3199,6 +3205,7 @@ function InnerEditor({
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<fieldset className="wf-inspector-fields" disabled={isBuiltin}>
|
||||
{selectedNode.data.kind === "prompt" ? (
|
||||
<>
|
||||
<label className="wf-field">
|
||||
|
||||
@@ -189,6 +189,15 @@ function builtinPrDef(): WorkflowDefinition {
|
||||
};
|
||||
}
|
||||
|
||||
async function selectBuiltinExecutePromptNode() {
|
||||
await screen.findByTestId("wf-readonly-banner");
|
||||
const promptNodes = await screen.findAllByTestId("wf-node-prompt");
|
||||
const executeNode = promptNodes.find((node) => within(node).queryByText("Execute"));
|
||||
expect(executeNode).toBeTruthy();
|
||||
fireEvent.click(executeNode!);
|
||||
return executeNode!;
|
||||
}
|
||||
|
||||
function edgeRenderableAssertion(definition: WorkflowDefinition) {
|
||||
const flow = irToFlow(definition);
|
||||
const nodeIds = new Set(flow.nodes.map((node) => node.id));
|
||||
@@ -643,6 +652,58 @@ describe("WorkflowNodeEditor", () => {
|
||||
expect(getPromptFullscreenOverlay()).toBeNull();
|
||||
});
|
||||
|
||||
it("shows a non-disabled expand button and read-only prompt for builtin workflow prompt nodes", async () => {
|
||||
vi.mocked(fetchWorkflows).mockResolvedValue([builtinDef()]);
|
||||
|
||||
render(<WorkflowNodeEditor isOpen onClose={() => {}} addToast={() => {}} />);
|
||||
|
||||
await selectBuiltinExecutePromptNode();
|
||||
const inspector = await screen.findByTestId("wf-node-inspector");
|
||||
expect(within(inspector).getByLabelText("Prompt")).toHaveAttribute("readonly");
|
||||
|
||||
const expand = within(inspector).getByRole("button", { name: "Expand prompt editor" });
|
||||
expect(expand).toBeInTheDocument();
|
||||
expect(expand).not.toBeDisabled();
|
||||
});
|
||||
|
||||
it("opens and collapses the fullscreen prompt editor for builtin workflows", async () => {
|
||||
vi.mocked(fetchWorkflows).mockResolvedValue([builtinDef()]);
|
||||
|
||||
render(<WorkflowNodeEditor isOpen onClose={() => {}} addToast={() => {}} />);
|
||||
|
||||
await selectBuiltinExecutePromptNode();
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Expand prompt editor" }));
|
||||
|
||||
const fullscreenPromptEditor = getPromptFullscreenOverlay();
|
||||
expect(fullscreenPromptEditor).toBeInTheDocument();
|
||||
expect(fullscreenPromptEditor).toHaveClass("wf-prompt-editor--fullscreen");
|
||||
expect(getPromptFullscreenTextarea()).toHaveAttribute("readonly");
|
||||
|
||||
fireEvent.click(within(fullscreenPromptEditor!).getByRole("button", { name: "Collapse prompt editor" }));
|
||||
|
||||
expect(getPromptFullscreenOverlay()).toBeNull();
|
||||
});
|
||||
|
||||
it("opens and collapses the fullscreen prompt editor for builtin workflows on mobile", async () => {
|
||||
mockWorkflowEditorViewport("mobile");
|
||||
vi.mocked(fetchWorkflows).mockResolvedValue([builtinDef()]);
|
||||
|
||||
render(<WorkflowNodeEditor isOpen onClose={() => {}} addToast={() => {}} />);
|
||||
|
||||
fireEvent.click(await screen.findByRole("button", { name: "Default coding workflow" }));
|
||||
await selectBuiltinExecutePromptNode();
|
||||
const inspector = await screen.findByTestId("wf-node-inspector");
|
||||
fireEvent.click(within(inspector).getByRole("button", { name: "Expand prompt editor" }));
|
||||
|
||||
const fullscreenPromptEditor = getPromptFullscreenOverlay();
|
||||
expect(fullscreenPromptEditor).toBeInTheDocument();
|
||||
expect(fullscreenPromptEditor).toHaveClass("wf-prompt-editor--fullscreen");
|
||||
|
||||
fireEvent.click(within(fullscreenPromptEditor!).getByRole("button", { name: "Collapse prompt editor" }));
|
||||
|
||||
expect(getPromptFullscreenOverlay()).toBeNull();
|
||||
});
|
||||
|
||||
it("persists mobile fullscreen prompt edits back to the inline textarea", async () => {
|
||||
mockWorkflowEditorViewport("mobile");
|
||||
vi.mocked(fetchWorkflows).mockResolvedValue([v2Def()]);
|
||||
|
||||
Reference in New Issue
Block a user