feat(FN-3950): reorder task form sections and document github tracking plac

Reorganized the TaskForm to move the GitHub tracking section and locked the create-form section order, with tests verifying the new layout and documentation added for the tracking placement in the dashboard guide.

Fusion-Task-Id: FN-3950
This commit is contained in:
Fusion
2026-05-10 16:07:52 -07:00
committed by gsxdsm
parent 8b56dff8b0
commit 60d16aa267
5 changed files with 60 additions and 38 deletions

View File

@@ -401,6 +401,7 @@ Inspect task definition, logs, review feedback, comments, documents, workflow ou
- Execution mode has a read-mode inline lightning-bolt toggle for Fast mode on/off without opening the full edit form. - Execution mode has a read-mode inline lightning-bolt toggle for Fast mode on/off without opening the full edit form.
- These two metadata controls share matched sizing/alignment in read mode (including mobile wrapping) so they behave like a single polished control group. - These two metadata controls share matched sizing/alignment in read mode (including mobile wrapping) so they behave like a single polished control group.
- Eligible existing tasks (triage, todo, in-progress, in-review) expose a **GitHub tracking** section directly in Task Detail, even when tracking is currently disabled. - Eligible existing tasks (triage, todo, in-progress, in-review) expose a **GitHub tracking** section directly in Task Detail, even when tracking is currently disabled.
- In shared task edit/create forms, GitHub Tracking appears at the bottom of **More options**, after **Workflow Steps**.
- From this section you can explicitly enable/disable tracking and manage a per-task repo override (`owner/repo`). Clearing the override saves `null` and falls back to project/global defaults. - From this section you can explicitly enable/disable tracking and manage a per-task repo override (`owner/repo`). Clearing the override saves `null` and falls back to project/global defaults.
- The **Review** tab is separate from **Comments**: Review shows actionable PR/reviewer feedback and same-task revision controls, while Comments remains the general collaboration thread. - The **Review** tab is separate from **Comments**: Review shows actionable PR/reviewer feedback and same-task revision controls, while Comments remains the general collaboration thread.
- **Request revision** in Review resumes work on the same task ID (no refinement task): `in-progress` tasks get steering injection, while `in-review` tasks are moved back to `in-progress` for the same branch/worktree revision pass. - **Request revision** in Review resumes work on the same task ID (no refinement task): `in-progress` tasks get steering injection, while `in-review` tasks are moved back to `in-progress` for the same branch/worktree revision pass.

View File

@@ -222,7 +222,7 @@ The task detail modal exposes multiple tabs.
In read mode, task metadata includes lightweight inline controls: priority can be changed from the priority chip, and execution mode can be toggled with a one-click lightning-bolt fast-mode button (Fast ↔ Standard) without opening full edit mode. These controls are intentionally aligned as a paired row (matched control height, baseline alignment, and mobile-safe wrapping) so frequent priority/mode changes stay quick and visually consistent. In read mode, task metadata includes lightweight inline controls: priority can be changed from the priority chip, and execution mode can be toggled with a one-click lightning-bolt fast-mode button (Fast ↔ Standard) without opening full edit mode. These controls are intentionally aligned as a paired row (matched control height, baseline alignment, and mobile-safe wrapping) so frequent priority/mode changes stay quick and visually consistent.
Task settings edited from the modal now auto-save as you edit (change/blur with debounce for text-like fields). This includes title, description, dependencies, working/base branch (`branch`/`baseBranch`), workflow-step selection, model overrides in the edit form, and source issue metadata. The footer Save button remains available, but normal field edits no longer depend on a manual save click. Task settings edited from the modal now auto-save as you edit (change/blur with debounce for text-like fields). This includes title, description, dependencies, working/base branch (`branch`/`baseBranch`), workflow-step selection, model overrides in the edit form, and source issue metadata. In shared create/edit task forms, the GitHub Tracking controls are placed at the bottom of **More options** after **Workflow Steps**. The footer Save button remains available, but normal field edits no longer depend on a manual save click.
The edit footer shows inline autosave state (saving/saved/error), and successful saves propagate the returned task through `onTaskUpdated` so open detail/list state stays fresh. The edit footer shows inline autosave state (saving/saved/error), and successful saves propagate the returned task through `onTaskUpdated` so open detail/list state stays fresh.

View File

@@ -999,43 +999,6 @@ export function TaskForm({
</div> </div>
)} )}
{(onGithubTrackingEnabledChange || onGithubRepoOverrideChange) && (
<div className="form-group" data-testid="task-form-github-tracking">
<label>GitHub Tracking</label>
{onGithubTrackingEnabledChange && (
<label className="checkbox-label" htmlFor="task-github-tracking-enabled">
<input
id="task-github-tracking-enabled"
type="checkbox"
checked={githubTrackingEnabled === true}
onChange={(event) => {
githubTrackingDefaultAppliedRef.current = true;
onGithubTrackingEnabledChange(event.target.checked);
}}
disabled={disabled}
/>
Enable GitHub issue tracking for this task
</label>
)}
{onGithubRepoOverrideChange && (
<>
<label htmlFor="task-github-repo-override" className="model-select-label">Repository (owner/repo)</label>
<input
id="task-github-repo-override"
className="input"
value={githubRepoOverride || ""}
onChange={(event) => onGithubRepoOverrideChange(event.target.value)}
placeholder={effectiveGithubRepoDefault || "owner/repo"}
disabled={disabled}
/>
{githubRepoOverrideInvalid ? (
<div className="form-error">Repository must be in owner/repo format.</div>
) : null}
</>
)}
</div>
)}
{/* Model Selection */} {/* Model Selection */}
<div className="form-group"> <div className="form-group">
<label>Model Configuration</label> <label>Model Configuration</label>
@@ -1315,6 +1278,43 @@ export function TaskForm({
</div> </div>
)} )}
</div> </div>
{(onGithubTrackingEnabledChange || onGithubRepoOverrideChange) && (
<div className="form-group" data-testid="task-form-github-tracking">
<label>GitHub Tracking</label>
{onGithubTrackingEnabledChange && (
<label className="checkbox-label" htmlFor="task-github-tracking-enabled">
<input
id="task-github-tracking-enabled"
type="checkbox"
checked={githubTrackingEnabled === true}
onChange={(event) => {
githubTrackingDefaultAppliedRef.current = true;
onGithubTrackingEnabledChange(event.target.checked);
}}
disabled={disabled}
/>
Enable GitHub issue tracking for this task
</label>
)}
{onGithubRepoOverrideChange && (
<>
<label htmlFor="task-github-repo-override" className="model-select-label">Repository (owner/repo)</label>
<input
id="task-github-repo-override"
className="input"
value={githubRepoOverride || ""}
onChange={(event) => onGithubRepoOverrideChange(event.target.value)}
placeholder={effectiveGithubRepoDefault || "owner/repo"}
disabled={disabled}
/>
{githubRepoOverrideInvalid ? (
<div className="form-error">Repository must be in owner/repo format.</div>
) : null}
</>
)}
</div>
)}
</div> </div>
</div> </div>
); );

View File

@@ -1071,6 +1071,19 @@ describe("NewTaskModal", () => {
}); });
describe("GitHub tracking", () => { describe("GitHub tracking", () => {
it("renders GitHub tracking after Workflow Steps in more options", async () => {
renderNewTaskModal();
fireEvent.click(screen.getByTestId("task-form-more-options-toggle"));
const workflowLabel = await screen.findByText("Workflow Steps");
const githubTrackingSection = screen.getByTestId("task-form-github-tracking");
expect(
workflowLabel.compareDocumentPosition(githubTrackingSection) & Node.DOCUMENT_POSITION_FOLLOWING,
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
});
it("seeds tracking toggle from project settings and submits githubTracking payload", async () => { it("seeds tracking toggle from project settings and submits githubTracking payload", async () => {
const { fetchSettings } = await import("../../api"); const { fetchSettings } = await import("../../api");
vi.mocked(fetchSettings).mockResolvedValueOnce({ vi.mocked(fetchSettings).mockResolvedValueOnce({

View File

@@ -1439,6 +1439,10 @@ describe("TaskForm focus behavior (FN-1459)", () => {
it("renders renderBelowModelConfiguration content below model section in More options", async () => { it("renders renderBelowModelConfiguration content below model section in More options", async () => {
renderTaskForm({ renderTaskForm({
renderBelowModelConfiguration: <div data-testid="injected-below-model">Bottom slot content</div>, renderBelowModelConfiguration: <div data-testid="injected-below-model">Bottom slot content</div>,
githubTrackingEnabled: false,
onGithubTrackingEnabledChange: vi.fn(),
githubRepoOverride: "",
onGithubRepoOverrideChange: vi.fn(),
}); });
const toggle = screen.getByTestId("task-form-more-options-toggle"); const toggle = screen.getByTestId("task-form-more-options-toggle");
@@ -1451,6 +1455,7 @@ describe("TaskForm focus behavior (FN-1459)", () => {
const modelLabel = screen.getByText("Model Configuration"); const modelLabel = screen.getByText("Model Configuration");
const workflowLabel = screen.getByText("Workflow Steps"); const workflowLabel = screen.getByText("Workflow Steps");
const injectedBottom = screen.getByTestId("injected-below-model"); const injectedBottom = screen.getByTestId("injected-below-model");
const githubTrackingSection = screen.getByTestId("task-form-github-tracking");
expect( expect(
modelLabel.compareDocumentPosition(injectedBottom) & Node.DOCUMENT_POSITION_FOLLOWING, modelLabel.compareDocumentPosition(injectedBottom) & Node.DOCUMENT_POSITION_FOLLOWING,
@@ -1458,6 +1463,9 @@ describe("TaskForm focus behavior (FN-1459)", () => {
expect( expect(
injectedBottom.compareDocumentPosition(workflowLabel) & Node.DOCUMENT_POSITION_FOLLOWING, injectedBottom.compareDocumentPosition(workflowLabel) & Node.DOCUMENT_POSITION_FOLLOWING,
).toBe(Node.DOCUMENT_POSITION_FOLLOWING); ).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
expect(
workflowLabel.compareDocumentPosition(githubTrackingSection) & Node.DOCUMENT_POSITION_FOLLOWING,
).toBe(Node.DOCUMENT_POSITION_FOLLOWING);
}); });
it("hides dependencies section when hideDependencies is true", async () => { it("hides dependencies section when hideDependencies is true", async () => {