feat(FN-2556): add TaskForm bottom slot for model configuration
- Add a new renderBelowModelConfiguration prop in TaskForm and render it beneath the Model Configuration section inside More options - Update TaskDetailModal to use the new slot so the Source Issue edit block appears below model settings instead of near the primary section - Adjust TaskDetailModal source-issue edit tests to expand More options before interacting with source fields - Add ordering assertions in TaskForm and TaskDetailModal tests to verify the injected block sits between Model Configuration and Workflow Steps
This commit is contained in:
@@ -1289,7 +1289,7 @@ export function TaskDetailModal({
|
||||
onPriorityChange={setEditPriority}
|
||||
executionMode={editExecutionMode}
|
||||
onExecutionModeChange={setEditExecutionMode}
|
||||
renderBelowPrimary={(
|
||||
renderBelowModelConfiguration={(
|
||||
<div className="form-group detail-source-edit-group">
|
||||
<label>Source Issue</label>
|
||||
<div className="detail-source-edit-grid">
|
||||
|
||||
@@ -90,6 +90,8 @@ export interface TaskFormProps {
|
||||
|
||||
/** Optional content to render between the primary section and the "More options" toggle. */
|
||||
renderBelowPrimary?: React.ReactNode;
|
||||
/** Optional content to render inside "More options" below Model Configuration. */
|
||||
renderBelowModelConfiguration?: React.ReactNode;
|
||||
/** When true, skip rendering the Dependencies form-group inside "More options". Use when the parent renders its own dependency UI via renderBelowPrimary. */
|
||||
hideDependencies?: boolean;
|
||||
/** When true (default), More options auto-expands when non-default advanced selections are present. */
|
||||
@@ -133,6 +135,7 @@ export function TaskForm({
|
||||
onSubtaskBreakdown,
|
||||
onClose,
|
||||
renderBelowPrimary,
|
||||
renderBelowModelConfiguration,
|
||||
hideDependencies,
|
||||
autoExpandMoreOptionsOnSelection = true,
|
||||
reviewLevel,
|
||||
@@ -1052,6 +1055,8 @@ export function TaskForm({
|
||||
)}
|
||||
</div>
|
||||
|
||||
{renderBelowModelConfiguration}
|
||||
|
||||
{/* Workflow Steps */}
|
||||
<div className="form-group" data-testid="workflow-steps-section">
|
||||
<label>Workflow Steps</label>
|
||||
|
||||
@@ -4198,6 +4198,7 @@ describe("TaskDetailModal", () => {
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(".modal-edit-btn")!);
|
||||
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
|
||||
|
||||
await waitFor(() => {
|
||||
expect((screen.getByTestId("task-source-provider-input") as HTMLInputElement).value).toBe("github");
|
||||
@@ -4207,6 +4208,45 @@ describe("TaskDetailModal", () => {
|
||||
expect((screen.getByTestId("task-source-url-input") as HTMLInputElement).value).toBe("https://github.com/runfusion/fusion/issues/2473");
|
||||
});
|
||||
|
||||
it("renders source issue block below Model Configuration in edit mode", async () => {
|
||||
const { container } = render(
|
||||
<TaskDetailModal
|
||||
task={makeTask({
|
||||
id: "FN-001",
|
||||
column: "todo",
|
||||
sourceIssue: {
|
||||
provider: "github",
|
||||
repository: "runfusion/fusion",
|
||||
externalIssueId: "I_kgDOExample",
|
||||
issueNumber: 2473,
|
||||
},
|
||||
})}
|
||||
onClose={noop}
|
||||
onMoveTask={noopMove}
|
||||
onDeleteTask={noopDelete}
|
||||
onMergeTask={noopMerge}
|
||||
onOpenDetail={noopOpenDetail}
|
||||
addToast={noop}
|
||||
/>,
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(".modal-edit-btn")!);
|
||||
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
|
||||
|
||||
await waitFor(() => {
|
||||
const modelLabel = screen.getByText("Model Configuration");
|
||||
const sourceLabel = screen.getByText("Source Issue");
|
||||
const workflowSection = screen.getByTestId("workflow-steps-section");
|
||||
|
||||
expect(
|
||||
modelLabel.compareDocumentPosition(sourceLabel) & Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
|
||||
expect(
|
||||
sourceLabel.compareDocumentPosition(workflowSection) & Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
|
||||
});
|
||||
});
|
||||
|
||||
it("sends sourceIssue payload when source metadata is edited", async () => {
|
||||
const { updateTask } = await import("../../api");
|
||||
const mockUpdate = vi.mocked(updateTask);
|
||||
@@ -4235,6 +4275,7 @@ describe("TaskDetailModal", () => {
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(".modal-edit-btn")!);
|
||||
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
|
||||
fireEvent.change(screen.getByTestId("task-source-provider-input"), { target: { value: "gitlab" } });
|
||||
fireEvent.change(screen.getByTestId("task-source-repository-input"), { target: { value: "runfusion/dashboard" } });
|
||||
fireEvent.change(screen.getByTestId("task-source-external-id-input"), { target: { value: "I_kgDONew" } });
|
||||
@@ -4283,6 +4324,7 @@ describe("TaskDetailModal", () => {
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(".modal-edit-btn")!);
|
||||
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
|
||||
fireEvent.change(screen.getByTestId("task-source-provider-input"), { target: { value: "" } });
|
||||
fireEvent.change(screen.getByTestId("task-source-repository-input"), { target: { value: "" } });
|
||||
fireEvent.change(screen.getByTestId("task-source-external-id-input"), { target: { value: "" } });
|
||||
@@ -4323,6 +4365,7 @@ describe("TaskDetailModal", () => {
|
||||
);
|
||||
|
||||
fireEvent.click(container.querySelector(".modal-edit-btn")!);
|
||||
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
|
||||
fireEvent.change(screen.getByTestId("task-source-provider-input"), { target: { value: "gitlab" } });
|
||||
fireEvent.click(screen.getByText("Save"));
|
||||
|
||||
|
||||
@@ -1382,6 +1382,30 @@ describe("TaskForm focus behavior (FN-1459)", () => {
|
||||
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
|
||||
});
|
||||
|
||||
it("renders renderBelowModelConfiguration content below model section in More options", async () => {
|
||||
renderTaskForm({
|
||||
renderBelowModelConfiguration: <div data-testid="injected-below-model">Bottom slot content</div>,
|
||||
});
|
||||
|
||||
const toggle = screen.getByTestId("task-form-more-options-toggle");
|
||||
fireEvent.click(toggle);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(toggle).toHaveAttribute("aria-expanded", "true");
|
||||
});
|
||||
|
||||
const modelLabel = screen.getByText("Model Configuration");
|
||||
const workflowLabel = screen.getByText("Workflow Steps");
|
||||
const injectedBottom = screen.getByTestId("injected-below-model");
|
||||
|
||||
expect(
|
||||
modelLabel.compareDocumentPosition(injectedBottom) & Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
|
||||
expect(
|
||||
injectedBottom.compareDocumentPosition(workflowLabel) & Node.DOCUMENT_POSITION_FOLLOWING,
|
||||
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
|
||||
});
|
||||
|
||||
it("hides dependencies section when hideDependencies is true", async () => {
|
||||
renderTaskForm({ hideDependencies: true });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user