diff --git a/.changeset/fn-7677-quick-add-workflow-trigger-height.md b/.changeset/fn-7677-quick-add-workflow-trigger-height.md new file mode 100644 index 0000000000..f540273671 --- /dev/null +++ b/.changeset/fn-7677-quick-add-workflow-trigger-height.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Align the quick-add workflow dropdown button height with Save/Fast/Subtask buttons. +category: fix +dev: `.quick-entry-workflow-trigger` in QuickEntryBox.css now re-asserts `.btn-sm`'s `padding: 4px 10px` locally so the shared global `.dep-trigger` `padding: 3px 8px` no longer shortens it by ~2px; other `.dep-trigger` surfaces (InlineCreateCard, NewTaskModal, TaskDetailModal, TaskForm) are unaffected (FN-7677). diff --git a/packages/cli/skill/fusion/references/extension-tools.md b/packages/cli/skill/fusion/references/extension-tools.md index 46ee4e8d4f..ae18e41de0 100644 --- a/packages/cli/skill/fusion/references/extension-tools.md +++ b/packages/cli/skill/fusion/references/extension-tools.md @@ -104,11 +104,12 @@ Request a refinement of a completed or in-review task. Creates a new follow-up t ### fn_task_archive -Archive a task from any live column (move to archived). Archived tasks are preserved for historical reference but moved out of the main board view. +Archive a task from any live column (move to archived). Archived tasks are preserved for historical reference but moved out of the main board view. If the task is still referenced as a lineage parent by another task, archiving is rejected unless removeLineageReferences:true is passed. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | ✓ | Task ID to archive from any live column (e.g. FN-001). | +| `removeLineageReferences` | boolean | — | When true, clear incoming lineage-parent references (child sourceParentTaskId) before archiving, so a task still referenced as a lineage parent can be archived. | ### fn_task_unarchive @@ -120,12 +121,13 @@ Unarchive an archived task (move from archived → its restore column). Restores ### fn_task_delete -Soft-delete a task from active Fusion board views. The task row and artifacts are preserved; optional allowResurrection marks the ID for intentional recreation. +Soft-delete a task from active Fusion board views. The task row and artifacts are preserved; optional allowResurrection marks the ID for intentional recreation. If the task is still referenced as a lineage parent by another task, deletion is rejected unless removeLineageReferences:true is passed. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| | `id` | string | ✓ | Task ID to delete (e.g. FN-001) | | `allowResurrection` | boolean | — | When true, mark this tombstone as explicitly reusable for future recreation. | +| `removeLineageReferences` | boolean | — | When true, clear incoming lineage-parent references (child sourceParentTaskId) before deleting, so a task still referenced as a lineage parent can be removed. | ### fn_task_browse_gitlab_project_issues diff --git a/packages/cli/skill/fusion/references/fusion-capabilities.md b/packages/cli/skill/fusion/references/fusion-capabilities.md index 674bd8b842..099f4a9ce0 100644 --- a/packages/cli/skill/fusion/references/fusion-capabilities.md +++ b/packages/cli/skill/fusion/references/fusion-capabilities.md @@ -30,9 +30,9 @@ All skill/extension tool invocations in this catalog use the public `fn_*` names | `fn_task_retry` | Retry a failed task — clears the error state. Non-review failures move to todo; in-review execution failures move to todo preserving progress; in-review merge failures stay in-place for auto-merge retry. | | `fn_task_duplicate` | Duplicate an existing task, creating a fresh copy in planning. Copies the title and description but resets all execution state. The AI planning agent will replan the new task. | | `fn_task_refine` | Request a refinement of a completed or in-review task. Creates a new follow-up task in planning that references the original task as a dependency. Use this when a done or in-review task needs additional work, improvements, or follow-up changes. | -| `fn_task_archive` | Archive a task from any live column (move to archived). Archived tasks are preserved for historical reference but moved out of the main board view. | +| `fn_task_archive` | Archive a task from any live column (move to archived). Archived tasks are preserved for historical reference but moved out of the main board view. If the task is still referenced as a lineage parent by another task, archiving is rejected unless removeLineageReferences:true is passed. | | `fn_task_unarchive` | Unarchive an archived task (move from archived → its restore column). Restores to the pre-archive column when available, with active execution columns downgraded to todo. | -| `fn_task_delete` | Soft-delete a task from active Fusion board views. The task row and artifacts are preserved; optional allowResurrection marks the ID for intentional recreation. | +| `fn_task_delete` | Soft-delete a task from active Fusion board views. The task row and artifacts are preserved; optional allowResurrection marks the ID for intentional recreation. If the task is still referenced as a lineage parent by another task, deletion is rejected unless removeLineageReferences:true is passed. | | `fn_task_import_github` | Import GitHub issues as Fusion tasks. Fetches open issues from a repository and creates tasks in the planning column. Each task includes the issue title and body with a link to the source issue. | | `fn_task_import_github_issue` | Import a specific GitHub issue as a Fusion task. Fetches the issue by number and creates a single task in the planning column with the issue title and body. | | `fn_task_browse_github_issues` | List open GitHub issues from a repository to browse before importing. Returns issue numbers, titles, and URLs for selection. Use with fn_task_import_github_issue to import specific issues by number. | diff --git a/packages/dashboard/app/__tests__/quick-entry-workflow-trigger-height.test.tsx b/packages/dashboard/app/__tests__/quick-entry-workflow-trigger-height.test.tsx new file mode 100644 index 0000000000..4c2626b056 --- /dev/null +++ b/packages/dashboard/app/__tests__/quick-entry-workflow-trigger-height.test.tsx @@ -0,0 +1,248 @@ +import { describe, it, expect, vi, beforeEach, afterEach } from "vitest"; +import { loadAllAppCss, loadStylesCss } from "../test/cssFixture"; +import { render, screen, act } from "@testing-library/react"; +import { QuickEntryBox } from "../components/QuickEntryBox"; +import type { Task } from "@fusion/core"; +import type { BoardWorkflowDefinition } from "../api"; +import { fetchAgents } from "../api"; + +/* +FNXC:QuickAddWorkflow 2026-07-08-00:00: +FN-7677 regression coverage. The workflow trigger shares `.dep-trigger` with +InlineCreateCard/NewTaskModal/TaskDetailModal/TaskForm, whose global rule sets +`padding: 3px 8px` and overrides `.btn-sm`'s `padding: 4px 10px`. That made the +quick-add trigger ~2px shorter than the sibling Save/Fast/Subtask `.btn.btn-sm` +buttons. These tests assert the local `.quick-entry-workflow-trigger` override +re-asserts `.btn-sm`'s own padding value (not a new hardcoded literal) so the +box heights resolve equal, and that the fix holds at desktop widths (not just +inside the mobile touch-target `min-height` media block), and that the shared +global `.dep-trigger` rule itself remains untouched for other surfaces. +*/ + +const mockTasks: Task[] = [ + { + id: "FN-001", + title: "Test task 1", + description: "First test task", + column: "todo", + dependencies: [], + steps: [], + currentStep: 0, + log: [], + createdAt: "2026-01-01T00:00:00Z", + updatedAt: "2026-01-01T00:00:00Z", + }, +]; + +const WORKFLOW_A: BoardWorkflowDefinition = { + id: "builtin:coding", + name: "Coding", + columns: [], +}; + +const WORKFLOW_B: BoardWorkflowDefinition = { + id: "wf-custom-long-name", + name: "A Rather Long Custom Workflow Name That Should Truncate", + columns: [], +}; + +vi.mock("../api", () => ({ + fetchModels: vi.fn().mockResolvedValue({ + models: [], + favoriteProviders: [], + favoriteModels: [], + }), + fetchSettings: vi.fn().mockResolvedValue({ + modelPresets: [], + autoSelectModelPreset: false, + defaultPresetBySize: {}, + maxConcurrent: 2, + maxWorktrees: 4, + pollIntervalMs: 30000, + groupOverlappingFiles: true, + autoMerge: true, + }), + fetchAgents: vi.fn().mockResolvedValue([]), + fetchWorkflowOptionalSteps: vi.fn().mockResolvedValue([]), + uploadAttachment: vi.fn().mockResolvedValue({}), + updateGlobalSettings: vi.fn().mockResolvedValue({}), +})); + +vi.mock("lucide-react", () => ({ + Link: () => null, + Paperclip: () => null, + Brain: () => null, + Lightbulb: () => null, + ListTree: () => null, + Sparkles: () => null, + Save: () => null, + X: () => null, + ChevronDown: () => null, + ChevronUp: () => null, + ChevronRight: () => null, + Bot: () => null, + Server: () => null, + Flag: () => null, + Maximize2: () => null, + Minimize2: () => null, +})); + +vi.mock("../components/ModelSelectionModal", () => ({ + ModelSelectionModal: () => null, +})); + +vi.mock("../components/CustomModelDropdown", () => ({ + CustomModelDropdown: ({ + value, + label, + }: { + value: string; + onChange: (value: string) => void; + label: string; + }) =>