From 1f0a48582d6704dc1329c924dfc5677a9a2467f4 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Tue, 23 Jun 2026 21:48:01 -0700 Subject: [PATCH] FN-6940: expose New Task quick-add actions Expose the regular New Task dialog's primary creation and quick-add controls in one visible action row. - Move the Create Task submit affordance into TaskForm's create-mode action cluster. - Promote GitHub tracking, workflow, model, node, fast mode, attach, priority, plan, and subtask controls as inline quick-add buttons. - Add responsive spacing and mobile touch-target coverage for the expanded action row. - Extend NewTaskModal and TaskForm tests around the promoted controls and submission flow. Files changed: packages/dashboard/app/components/NewTaskModal.css | 12 ++ packages/dashboard/app/components/NewTaskModal.tsx | 10 +- packages/dashboard/app/components/TaskForm.tsx | 110 +++++++++++++++- .../app/components/__tests__/NewTaskModal.test.tsx | 139 ++++++++++++++++++--- .../app/components/__tests__/TaskForm.test.tsx | 3 + .../__tests__/core-modals-mobile.test.tsx | 8 +- 6 files changed, 250 insertions(+), 32 deletions(-) Fusion-Task-Id: FN-6940 Fusion-Task-Lineage: 8329c432-5e01-40aa-a3da-c13754a74393 --- .../dashboard/app/components/NewTaskModal.css | 12 ++ .../dashboard/app/components/NewTaskModal.tsx | 10 +- .../dashboard/app/components/TaskForm.tsx | 110 +++++++++++++- .../__tests__/NewTaskModal.test.tsx | 137 +++++++++++++++--- .../components/__tests__/TaskForm.test.tsx | 3 + .../__tests__/core-modals-mobile.test.tsx | 8 +- 6 files changed, 249 insertions(+), 31 deletions(-) diff --git a/packages/dashboard/app/components/NewTaskModal.css b/packages/dashboard/app/components/NewTaskModal.css index b0d16768d1..e767247666 100644 --- a/packages/dashboard/app/components/NewTaskModal.css +++ b/packages/dashboard/app/components/NewTaskModal.css @@ -187,6 +187,13 @@ Edge + corner resize handles. touch-action:none keeps the drag from being hijack .task-form-description-actions .btn { border-color: var(--border); + align-items: center; + gap: var(--space-xs); + white-space: nowrap; +} + +.task-form-action-icon { + vertical-align: middle; } .task-form-more-options-toggle { @@ -595,6 +602,11 @@ Edge + corner resize handles. touch-action:none keeps the drag from being hijack gap: var(--space-xs); } + .task-form-description-actions .btn { + min-height: 36px; + flex: 1 1 auto; + } + .task-form-more-options-toggle { margin: 0 var(--space-md) var(--space-sm); width: calc(100% - var(--space-md) * 2); diff --git a/packages/dashboard/app/components/NewTaskModal.tsx b/packages/dashboard/app/components/NewTaskModal.tsx index a159edb366..2e11caa81a 100644 --- a/packages/dashboard/app/components/NewTaskModal.tsx +++ b/packages/dashboard/app/components/NewTaskModal.tsx @@ -886,6 +886,9 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask, onGithubTrackingEnabledChange={setGithubTrackingEnabled} githubRepoOverride={githubRepoOverride} onGithubRepoOverrideChange={setGithubRepoOverride} + onCreateSubmit={handleSubmit} + createSubmitLabel={isSubmitting ? t("newTaskModal.creating", "Creating...") : t("newTaskModal.createTask", "Create Task")} + createSubmitDisabled={!description.trim() || isSubmitting || githubRepoOverrideInvalid || hasInvalidBranchSelection} renderBelowPrimary={quickFields} hideDependencies={true} autoExpandMoreOptionsOnSelection={false} @@ -901,13 +904,6 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask, - diff --git a/packages/dashboard/app/components/TaskForm.tsx b/packages/dashboard/app/components/TaskForm.tsx index 842c605f42..96f27eb2ec 100644 --- a/packages/dashboard/app/components/TaskForm.tsx +++ b/packages/dashboard/app/components/TaskForm.tsx @@ -8,8 +8,9 @@ import { applyPresetToSelection, getRecommendedPresetForSize } from "../utils/mo import { CustomModelDropdown } from "./CustomModelDropdown"; import { NodeHealthDot } from "./NodeHealthDot"; import { LoadingSpinner } from "./LoadingSpinner"; -import { Sparkles, ChevronUp, ChevronDown, Maximize2, Minimize2, Paperclip, Flag, Zap } from "lucide-react"; +import { Sparkles, ChevronUp, ChevronDown, Maximize2, Minimize2, Paperclip, Flag, Zap, Brain, Server } from "lucide-react"; import { REPO_OVERRIDE_RE, resolveEffectiveGithubRepoDefault } from "./githubTracking"; +import { ProviderIcon } from "./ProviderIcon"; function getNodeStatusLabel(status: NodeInfo["status"], t: (key: string, defaultValue: string) => string): string { if (status === "online") return t("taskForm.nodeStatusOnline", "Online"); @@ -138,6 +139,12 @@ export interface TaskFormProps { onSubtaskBreakdown?: (description: string, workflowId?: string | null) => void; onClose?: () => void; + // Create-mode primary submission. NewTaskModal owns duplicate checks and payload shaping; + // TaskForm only places the visible Create affordance in the quick-action row. + onCreateSubmit?: () => void; + createSubmitLabel?: string; + createSubmitDisabled?: boolean; + /** 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. */ @@ -204,6 +211,9 @@ export function TaskForm({ onPlanningMode, onSubtaskBreakdown, onClose, + onCreateSubmit, + createSubmitLabel, + createSubmitDisabled, renderBelowPrimary, renderBelowModelConfiguration, hideDependencies, @@ -697,6 +707,22 @@ export function TaskForm({ // U6/R3: the project default workflow id (preselected + "(default)" badged). const defaultWorkflowId = settings?.defaultWorkflowId ?? null; + const selectedWorkflow = selectedWorkflowId === null + ? null + : workflows.find((workflow) => workflow.id === (selectedWorkflowId ?? defaultWorkflowId)); + const workflowInlineLabel = selectedWorkflowId === null + ? t("taskForm.workflowNone", "No workflow") + : selectedWorkflow?.name ?? t("taskForm.workflowInlineDefault", "Normal"); + const selectedNode = (nodeOptions ?? []).find((node) => node.id === nodeId); + const nodeInlineLabel = selectedNode?.name ?? t("taskForm.nodeInlineDefault", "Node"); + const modelInlineLabel = selectedPreset?.name ?? (presetMode === "custom" ? t("taskForm.modelsCustom", "Models") : t("taskForm.modelsDefault", "Models")); + + const revealAdvancedControl = useCallback((selector: string) => { + if (!forceMoreOptionsOpen) setShowMoreOptions(true); + window.setTimeout(() => { + document.querySelector(selector)?.focus(); + }, 0); + }, [forceMoreOptionsOpen]); const availableDeps = tasks .filter((t) => !dependencies.includes(t.id)) @@ -847,9 +873,23 @@ export function TaskForm({ - Fast → toggles executionMode standard⇄fast via onExecutionModeChange (mirrors QuickEntryBox quick-entry-fast-toggle). - Priority → cycles through TASK_PRIORITIES via onPriorityChange (Flag affordance). Plan/Subtask remain gated on their handoff callbacks. Model selectors, branch/base, node, review level, and GitHub tracking stay in the Advanced disclosure. + + FNXC:NewTaskDialogAffordances 2026-06-23-21:20: + The regular New Task dialog must visibly expose the screenshot quick-add button contract in the immediate action cluster while Advanced remains the deep configuration editor. TaskForm hosts the cluster so create payload state has one source of truth; NewTaskModal only supplies the submit handler and its existing dependency/agent quick controls. */} {mode === "create" && (
+ {onCreateSubmit && ( + + )} {onPlanningMode && ( )} + {/* FNXC:NewTaskDialogAffordances 2026-06-23-21:31: GitHub/workflow/models/node are promoted as visible chips that mutate or focus the same Advanced controls instead of duplicating create-payload state. */} + {onGithubTrackingEnabledChange && ( + + )} + + {onWorkflowIdChange && ( + + )} + + + + {onNodeIdChange && ( + + )} + {/* FNXC:NewTask 2026-06-23-00:10: Priority — cycles TASK_PRIORITIES via onPriorityChange (Flag affordance, same label shape as QuickEntryBox). */} {onPriorityChange && (