Address PR review feedback (#1703)

- Dropdown: aria-multiselectable, drop dead aria-labelledby, ArrowUp opens panel
- Dirty-state: NewTaskModal tracks enabledWorkflowSteps so toggles trigger discard prompt
- TaskForm: reset optionalStepsLoading on the no-workflow early return
- Node editor: pass plugin step templates into the optional-steps panel (both layouts)
- FNXC requirement comments on the new optional-steps components
This commit is contained in:
gsxdsm
2026-06-21 03:00:40 -07:00
parent e16d48910c
commit 45dc1795ef
7 changed files with 32 additions and 4 deletions

View File

@@ -1083,6 +1083,10 @@ export function InlineCreateCard({
className="inline-create-optional-steps"
aria-label={t("inline.optionalWorkflowSteps", "Optional workflow steps")}
>
{/* FNXC:TaskCreation 2026-06-21-00:00:
Inline quick-add uses the shared optional-steps dropdown so it matches
the modal/quick-add keyboard + a11y behavior and toggles the same
enabledWorkflowSteps set submitted on create. */}
<WorkflowOptionalStepsDropdown
steps={optionalSteps}
enabledIds={enabledOptionalStepIds}

View File

@@ -164,6 +164,10 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
dependencies.length > 0 ||
pendingImages.length > 0 ||
selectedWorkflowId !== undefined ||
// Optional workflow steps the user toggled count as unsaved work. (Workflows
// whose steps are defaultOn:false — today's only shipped step — seed an empty
// set, so this stays false until the user actually opts a step in.)
enabledWorkflowSteps.length > 0 ||
executorModel !== "" ||
validatorModel !== "" ||
planningModel !== "" ||
@@ -179,7 +183,7 @@ export function NewTaskModal({ isOpen, onClose, projectId, tasks, onCreateTask,
githubTrackingEnabled ||
githubRepoOverrideTrimmed !== "";
setHasDirtyState(isDirty);
}, [description, dependencies, pendingImages, selectedWorkflowId, executorModel, validatorModel, planningModel, thinkingLevel, selectedAgentId, reviewLevel, autoMerge, priority, nodeId, branchMode, branch, baseBranch, githubTrackingEnabled, githubRepoOverrideTrimmed]);
}, [description, dependencies, pendingImages, selectedWorkflowId, enabledWorkflowSteps, executorModel, validatorModel, planningModel, thinkingLevel, selectedAgentId, reviewLevel, autoMerge, priority, nodeId, branchMode, branch, baseBranch, githubTrackingEnabled, githubRepoOverrideTrimmed]);
const handleClose = useCallback(async () => {
if (hasDirtyState) {

View File

@@ -306,6 +306,9 @@ export function TaskForm({
let cancelled = false;
setOptionalSteps([]);
if (!effectiveOptionalWorkflowId) {
// Clear any in-flight loading state (a prior fetch may have been cancelled
// mid-flight when switching to "No workflow"), so the loading row never sticks.
setOptionalStepsLoading(false);
onEnabledWorkflowStepsChange?.([]);
return;
}

View File

@@ -2502,6 +2502,7 @@ function InnerEditor({
optionalSteps={optionalSteps}
onChange={setOptionalSteps}
readOnly={isBuiltin}
pluginTemplates={pluginTemplates.map((p) => p.template)}
/>
)}
</section>
@@ -2812,6 +2813,7 @@ function InnerEditor({
optionalSteps={optionalSteps}
onChange={setOptionalSteps}
readOnly={isBuiltin}
pluginTemplates={pluginTemplates.map((p) => p.template)}
/>
</div>
)}

View File

@@ -1,4 +1,9 @@
/**
* FNXC:WorkflowOptionalSteps 2026-06-21-00:00:
* Users selecting optional workflow steps at task creation need one consistent
* multi-select control across every creation surface, with full keyboard + screen-
* reader support, so the quick-add card and the full New Task modal behave identically.
*
* WorkflowOptionalStepsDropdown — a controlled multi-select for a workflow's
* optional steps, shared by the quick-add card (U5) and the full New Task modal
* (U4) so both creation surfaces present the same interaction.
@@ -109,10 +114,11 @@ export function WorkflowOptionalStepsDropdown({
: t("workflowOptionalSteps.triggerCount", "Steps: {{count}} selected", { count: selectedCount });
const onTriggerKeyDown = (e: React.KeyboardEvent) => {
if (e.key === "ArrowDown" || e.key === "Enter" || e.key === " ") {
// ArrowUp also opens (ARIA listbox authoring guidance), landing on the last option.
if (e.key === "ArrowDown" || e.key === "ArrowUp" || e.key === "Enter" || e.key === " ") {
e.preventDefault();
setIsOpen(true);
setActiveIndex(0);
setActiveIndex(e.key === "ArrowUp" ? steps.length - 1 : 0);
}
};
@@ -161,8 +167,8 @@ export function WorkflowOptionalStepsDropdown({
ref={panelRef}
className="wf-optional-steps-dropdown-panel"
role="listbox"
aria-multiselectable="true"
aria-label={t("workflowOptionalSteps.title", "Optional steps")}
aria-labelledby={labelId}
data-testid="wf-optional-steps-dropdown-panel"
style={{ top: position.top, left: position.left, minWidth: position.width }}
onKeyDown={onPanelKeyDown}

View File

@@ -1,4 +1,9 @@
/**
* FNXC:WorkflowOptionalSteps 2026-06-21-00:00:
* Workflow authors need to declare which step templates are optional and set each
* one's defaultOn from the visual editor (persisted on the IR's `optionalSteps`
* array) so optional steps are authorable without hand-editing IR.
*
* WorkflowOptionalStepsPanel — the workflow editor's optional-step authoring
* surface. Sibling to {@link WorkflowFieldsPanel} / WorkflowSettingsPanel: lives
* alongside the canvas in {@link WorkflowNodeEditor} and mutates the IR's

View File

@@ -1,4 +1,8 @@
/**
* FNXC:WorkflowOptionalSteps 2026-06-21-00:00:
* One phase chip (pre-merge / post-merge) shared by every workflow-step surface so
* the badge looks identical across the results tab, authoring panel, and dropdown.
*
* Shared phase chip for workflow steps (pre-merge / post-merge). Extracted from
* WorkflowResultsTab so the node-editor optional-steps panel and the optional-step
* dropdown render an identical badge without duplicating markup.