diff --git a/ui/src/components/ActiveAgentsPanel.tsx b/ui/src/components/ActiveAgentsPanel.tsx index 2c2b0fcf295..4ff1c2cedba 100644 --- a/ui/src/components/ActiveAgentsPanel.tsx +++ b/ui/src/components/ActiveAgentsPanel.tsx @@ -27,7 +27,7 @@ function RunCardRecoveryChip({ action }: { action: IssueRecoveryAction }) { data-recovery-state={state} role="status" aria-label={tone.label} - title={`${tone.label} — open the source task to act.`} + title={`${tone.label} — open the source issue to act.`} className={cn( "inline-flex shrink-0 items-center gap-0.5 rounded-full border px-1.5 py-0.5 text-[10px] font-medium", tone.className, diff --git a/ui/src/components/ActivityCharts.tsx b/ui/src/components/ActivityCharts.tsx index bd3dd22adb0..591bcc4e89c 100644 --- a/ui/src/components/ActivityCharts.tsx +++ b/ui/src/components/ActivityCharts.tsx @@ -144,7 +144,7 @@ export function PriorityChart({ issues }: { issues: { priority: string; createdA const maxValue = Math.max(...Array.from(grouped.values()).map(v => Object.values(v).reduce((a, b) => a + b, 0)), 1); const hasData = Array.from(grouped.values()).some(v => Object.values(v).reduce((a, b) => a + b, 0) > 0); - if (!hasData) return

No tasks

; + if (!hasData) return

No issues

; return (
@@ -211,7 +211,7 @@ export function IssueStatusChart({ issues }: { issues: { status: string; created const maxValue = Math.max(...Array.from(grouped.values()).map(v => Object.values(v).reduce((a, b) => a + b, 0)), 1); const hasData = allStatuses.size > 0; - if (!hasData) return

No tasks

; + if (!hasData) return

No issues

; return (
diff --git a/ui/src/components/AgentConfigForm.tsx b/ui/src/components/AgentConfigForm.tsx index 9532ba5d2da..e07e97349f5 100644 --- a/ui/src/components/AgentConfigForm.tsx +++ b/ui/src/components/AgentConfigForm.tsx @@ -794,7 +794,7 @@ export function AgentConfigForm(props: AgentConfigFormProps) {
setParentSearch(e.target.value)} autoFocus={!inline} @@ -1693,11 +1693,11 @@ export function IssueProperties({ <> setBlockedBySearch(e.target.value)} autoFocus={!inline} - aria-label="Search tasks to add as blockers" + aria-label="Search issues to add as blockers" />
+
Searching issues...
) : blockerOptions.length === 0 ? ( -
No matching tasks.
+
No matching issues.
) : null}
@@ -1913,7 +1913,7 @@ export function IssueProperties({ ) : null} - +
{childIssues.length > 0 ? childIssues.map((child) => ( @@ -1927,7 +1927,7 @@ export function IssueProperties({ onClick={onAddSubIssue} > - Add sub-task + Add sub-issue ) : null}
diff --git a/ui/src/components/IssueRecoveryActionCard.test.tsx b/ui/src/components/IssueRecoveryActionCard.test.tsx index 0ddf1fd1259..5b80ceca439 100644 --- a/ui/src/components/IssueRecoveryActionCard.test.tsx +++ b/ui/src/components/IssueRecoveryActionCard.test.tsx @@ -134,7 +134,7 @@ describe("IssueRecoveryActionCard", () => { expect(node.textContent).toContain("RECOVERY NEEDED"); expect(node.textContent).toContain("Missing Disposition"); expect(node.textContent).not.toContain("missing_disposition"); - expect(node.textContent).toContain("This task's run finished, but no next step was chosen."); + expect(node.textContent).toContain("This issue's run finished, but no next step was chosen."); expect(node.textContent).toContain("ClaudeCoder"); expect(node.textContent).toContain("CodexCoder"); expect(node.textContent).toContain("Choose and record a valid issue disposition."); @@ -173,7 +173,7 @@ describe("IssueRecoveryActionCard", () => { click(node.querySelector("[data-testid='recovery-action-resolve-trigger']")); expect(document.body.textContent).toContain("Try again"); - expect(document.body.textContent).toContain("Mark task done"); + expect(document.body.textContent).toContain("Mark issue done"); expect(document.body.textContent).not.toContain("Mark blocked"); expect(document.body.textContent).not.toContain("Delegate follow-up issue"); click([...document.body.querySelectorAll("button")].find((button) => button.textContent?.includes("Try again")) ?? null); @@ -188,7 +188,7 @@ describe("IssueRecoveryActionCard", () => { click(node.querySelector("[data-testid='recovery-action-resolve-trigger']")); expect(document.body.textContent).toContain("Try again"); - expect(document.body.textContent).toContain("Mark task done"); + expect(document.body.textContent).toContain("Mark issue done"); expect(document.body.textContent).toContain("Send for review"); expect(document.body.textContent).toContain("False positive, done"); expect(document.body.textContent).toContain("False positive, review"); diff --git a/ui/src/components/IssueRecoveryActionCard.tsx b/ui/src/components/IssueRecoveryActionCard.tsx index fff3c56a60d..16ce3f5f194 100644 --- a/ui/src/components/IssueRecoveryActionCard.tsx +++ b/ui/src/components/IssueRecoveryActionCard.tsx @@ -45,19 +45,19 @@ export interface IssueRecoveryActionCardProps { const KIND_LABEL: Record = { missing_disposition: "Missing Disposition", - stranded_assigned_issue: "Stranded Task", + stranded_assigned_issue: "Stranded Issue", active_run_watchdog: "Active Watchdog", issue_graph_liveness: "Graph Liveness", }; const KIND_HEADLINE: Record = { - missing_disposition: "This task's run finished, but no next step was chosen.", + missing_disposition: "This issue's run finished, but no next step was chosen.", stranded_assigned_issue: - "Paperclip retried this task's last run and it still has no live execution path.", + "Paperclip retried this issue's last run and it still has no live execution path.", active_run_watchdog: "The active run has been silent. Recovery is observing without interrupting it.", issue_graph_liveness: - "Paperclip detected this task lost a live action path. A recovery owner needs to act.", + "Paperclip detected this issue lost a live action path. A recovery owner needs to act.", }; const STATE_TONE: Record {content} @@ -50,7 +50,7 @@ export function IssueReferencePill({ data-mention-kind="issue" className={classNames} title={issue.title} - aria-label={`Task ${issueLabel}: ${issue.title}`} + aria-label={`Issue ${issueLabel}: ${issue.title}`} > {content} diff --git a/ui/src/components/IssueRelatedWorkPanel.test.tsx b/ui/src/components/IssueRelatedWorkPanel.test.tsx index a2273849794..d1bd505f3ed 100644 --- a/ui/src/components/IssueRelatedWorkPanel.test.tsx +++ b/ui/src/components/IssueRelatedWorkPanel.test.tsx @@ -55,8 +55,8 @@ describe("IssueRelatedWorkPanel", () => { expect(html).toContain("Referenced by"); expect(html).toContain("PAP-22"); expect(html).toContain("PAP-33"); - expect(html).toContain('aria-label="Task PAP-22: Downstream task"'); - expect(html).toContain('aria-label="Task PAP-33: Upstream task"'); + expect(html).toContain('aria-label="Issue PAP-22: Downstream task"'); + expect(html).toContain('aria-label="Issue PAP-33: Upstream task"'); expect(html).toContain("plan"); expect(html).toContain("comment"); }); diff --git a/ui/src/components/IssueRelatedWorkPanel.tsx b/ui/src/components/IssueRelatedWorkPanel.tsx index b3072807f46..0e5bcd8d792 100644 --- a/ui/src/components/IssueRelatedWorkPanel.tsx +++ b/ui/src/components/IssueRelatedWorkPanel.tsx @@ -95,15 +95,15 @@ export function IssueRelatedWorkPanel({
); diff --git a/ui/src/components/IssueRow.tsx b/ui/src/components/IssueRow.tsx index 4825500c04a..d2d505146e3 100644 --- a/ui/src/components/IssueRow.tsx +++ b/ui/src/components/IssueRow.tsx @@ -244,7 +244,7 @@ function renderRecoveryChip(action: IssueRecoveryAction, selected: boolean): Rea tone.className, selected ? "!border-muted-foreground !text-muted-foreground" : null, )} - title={`${tone.label} — open the source task to act.`} + title={`${tone.label} — open the source issue to act.`} > {tone.label} diff --git a/ui/src/components/IssueRunLedger.tsx b/ui/src/components/IssueRunLedger.tsx index 4746aea0802..ca0967877d6 100644 --- a/ui/src/components/IssueRunLedger.tsx +++ b/ui/src/components/IssueRunLedger.tsx @@ -75,7 +75,7 @@ const LIVENESS_COPY: Record = { completed: { label: "Completed", tone: "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300", - description: "Task reached a terminal state.", + description: "Issue reached a terminal state.", }, advanced: { label: "Advanced", @@ -95,7 +95,7 @@ const LIVENESS_COPY: Record = { blocked: { label: "Blocked", tone: "border-yellow-500/30 bg-yellow-500/10 text-yellow-700 dark:text-yellow-300", - description: "Run or task declared a blocker.", + description: "Run or issue declared a blocker.", }, failed: { label: "Failed", @@ -535,7 +535,7 @@ export function IssueRunLedgerContent({ }, [activityEvents, canRenderActivityEvents, ledgerRuns]); return ( -
+

Run ledger

@@ -678,8 +678,8 @@ export function IssueRunLedgerContent({ {feedItems.length === 0 ? (
{renderActivityEvent - ? "Runs and activity will appear here once this task has history." - : "Historical runs without liveness metadata will appear here once linked to this task."} + ? "Runs and activity will appear here once this issue has history." + : "Historical runs without liveness metadata will appear here once linked to this issue."}
) : (
diff --git a/ui/src/components/IssueSiblingNavigation.test.tsx b/ui/src/components/IssueSiblingNavigation.test.tsx index abcbdab3258..d356fcfb775 100644 --- a/ui/src/components/IssueSiblingNavigation.test.tsx +++ b/ui/src/components/IssueSiblingNavigation.test.tsx @@ -84,7 +84,7 @@ describe("IssueSiblingNavigation", () => { ); const nav = node.querySelector("nav"); - expect(nav?.getAttribute("aria-label")).toBe("Sub-task navigation"); + expect(nav?.getAttribute("aria-label")).toBe("Sub-issue navigation"); expect(nav?.className).toContain("sm:grid-cols-2"); expect(nav?.className).not.toContain("border-t"); @@ -93,13 +93,13 @@ describe("IssueSiblingNavigation", () => { expect(links[0].textContent).toContain("Previous"); expect(links[0].textContent).toContain("PAP-1"); expect(links[0].textContent).toContain("Previous sibling title"); - expect(links[0].getAttribute("aria-label")).toBe("Previous sub-task: PAP-1 - Previous sibling title"); + expect(links[0].getAttribute("aria-label")).toBe("Previous sub-issue: PAP-1 - Previous sibling title"); expect(links[0].getAttribute("data-quicklook-align")).toBe("start"); expect(links[1].textContent).toContain("Next"); expect(links[1].textContent).toContain("PAP-3"); expect(links[1].textContent).toContain("Next sibling title"); - expect(links[1].getAttribute("aria-label")).toBe("Next sub-task: PAP-3 - Next sibling title"); + expect(links[1].getAttribute("aria-label")).toBe("Next sub-issue: PAP-3 - Next sibling title"); expect(links[1].getAttribute("data-quicklook-align")).toBe("end"); expect(links[1].className).toContain("sm:text-right"); diff --git a/ui/src/components/IssueSiblingNavigation.tsx b/ui/src/components/IssueSiblingNavigation.tsx index f5d2e7e480d..213dfe4d468 100644 --- a/ui/src/components/IssueSiblingNavigation.tsx +++ b/ui/src/components/IssueSiblingNavigation.tsx @@ -16,7 +16,7 @@ export function IssueSiblingNavigation({ navigation, linkState }: IssueSiblingNa return (
) : summary.totalCount === 0 ? ( -
No active sub-tasks
+
No active sub-issues
) : summary.doneCount === summary.totalCount ? ( -
All sub-tasks done
+
All sub-issues done
) : ( -
No actionable sub-tasks
+
No actionable sub-issues
)}
@@ -1289,8 +1289,8 @@ export function IssuesList({ viewState.groupBy, ]); - const createActionLabel = createIssueLabel ? `Create ${createIssueLabel}` : "Create Task"; - const createButtonLabel = createIssueLabel ? `New ${createIssueLabel}` : "New Task"; + const createActionLabel = createIssueLabel ? `Create ${createIssueLabel}` : "Create Issue"; + const createButtonLabel = createIssueLabel ? `New ${createIssueLabel}` : "New Issue"; const openCreateIssueDialog = useCallback((group?: { key: string; items: Issue[] }) => { openNewIssue(newIssueDefaults(group)); }, [newIssueDefaults, openNewIssue]); @@ -1461,7 +1461,7 @@ export function IssuesList({ visibleColumnSet={visibleIssueColumnSet} onToggleColumn={toggleIssueColumn} onResetColumns={() => setIssueColumns(DEFAULT_INBOX_ISSUE_COLUMNS)} - title="Choose which task columns stay visible" + title="Choose which issue columns stay visible" iconOnly /> @@ -1539,7 +1539,7 @@ export function IssuesList({ ["assignee", "Assignee"], ["project", "Project"], ["workspace", "Workspace"], - ["parent", "Parent Task"], + ["parent", "Parent Issue"], ["none", "None"], ] as const).map(([value, label]) => (
- Uses the shared chat-style run surface from task activity. + Uses the shared chat-style run surface from issue activity.
diff --git a/ui/src/components/MobileBottomNav.tsx b/ui/src/components/MobileBottomNav.tsx index 4a347007cfe..81006b59ae2 100644 --- a/ui/src/components/MobileBottomNav.tsx +++ b/ui/src/components/MobileBottomNav.tsx @@ -1,5 +1,4 @@ import { useMemo } from "react"; -import { useQuery } from "@tanstack/react-query"; import { NavLink, useLocation } from "@/lib/router"; import { House, @@ -10,8 +9,6 @@ import { } from "lucide-react"; import { useCompany } from "../context/CompanyContext"; import { useDialogActions } from "../context/DialogContext"; -import { instanceSettingsApi } from "../api/instanceSettings"; -import { queryKeys } from "../lib/queryKeys"; import { SIDEBAR_SCROLL_RESET_STATE } from "../lib/navigation-scroll"; import { cn } from "../lib/utils"; import { useInboxBadge } from "../hooks/useInboxBadge"; @@ -42,17 +39,11 @@ export function MobileBottomNav({ visible }: MobileBottomNavProps) { const { selectedCompanyId } = useCompany(); const { openNewIssue } = useDialogActions(); const inboxBadge = useInboxBadge(selectedCompanyId); - const { data: experimentalSettings } = useQuery({ - queryKey: queryKeys.instance.experimentalSettings, - queryFn: () => instanceSettingsApi.getExperimental(), - }); - // IA flag (PAP-89): mirror the sidebar's classic/streamlined label set. - const streamlined = experimentalSettings?.enableStreamlinedLeftNavigation === true; const items = useMemo( () => [ { type: "link", to: "/dashboard", label: "Home", icon: House }, - { type: "link", to: "/issues", label: streamlined ? "Tasks" : "Issues", icon: CircleDot }, + { type: "link", to: "/issues", label: "Issues", icon: CircleDot }, { type: "action", label: "Create", icon: SquarePen, onClick: () => openNewIssue() }, { type: "link", to: "/agents/all", label: "Agents", icon: Users }, { @@ -63,7 +54,7 @@ export function MobileBottomNav({ visible }: MobileBottomNavProps) { badge: inboxBadge.inbox, }, ], - [openNewIssue, inboxBadge.inbox, streamlined], + [openNewIssue, inboxBadge.inbox], ); return ( diff --git a/ui/src/components/NewIssueDialog.test.tsx b/ui/src/components/NewIssueDialog.test.tsx index ed9ddc9067d..b2627f721fe 100644 --- a/ui/src/components/NewIssueDialog.test.tsx +++ b/ui/src/components/NewIssueDialog.test.tsx @@ -352,11 +352,11 @@ describe("NewIssueDialog", () => { const { root } = renderDialog(container); await flush(); - expect(container.textContent).toContain("New sub-task"); - expect(container.textContent).toContain("Sub-task of"); + expect(container.textContent).toContain("New sub-issue"); + expect(container.textContent).toContain("Sub-issue of"); expect(container.textContent).toContain("PAP-1"); expect(container.textContent).toContain("Parent issue"); - expect(container.textContent).toContain("Create Sub-Task"); + expect(container.textContent).toContain("Create Sub-Issue"); act(() => root.unmount()); @@ -364,9 +364,9 @@ describe("NewIssueDialog", () => { const rerendered = renderDialog(container); await flush(); - expect(container.textContent).toContain("New task"); - expect(container.textContent).toContain("Create Task"); - expect(container.textContent).not.toContain("Sub-task of"); + expect(container.textContent).toContain("New issue"); + expect(container.textContent).toContain("Create Issue"); + expect(container.textContent).not.toContain("Sub-issue of"); act(() => rerendered.root.unmount()); }); @@ -421,7 +421,7 @@ describe("NewIssueDialog", () => { expect(mockExecutionWorkspacesApi.list).not.toHaveBeenCalled(); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Sub-Task")); + .find((button) => button.textContent?.includes("Create Sub-Issue")); expect(submitButton).not.toBeUndefined(); await waitForAssertion(() => { expect(submitButton?.hasAttribute("disabled")).toBe(false); @@ -460,7 +460,7 @@ describe("NewIssueDialog", () => { expect(planningButton?.className).toContain("bg-accent"); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Task")); + .find((button) => button.textContent?.includes("Create Issue")); expect(submitButton).not.toBeUndefined(); await vi.waitFor(() => { expect(submitButton?.hasAttribute("disabled")).toBe(false); @@ -531,14 +531,14 @@ describe("NewIssueDialog", () => { const { root } = renderDialog(container); await flush(); - expect(container.textContent).toContain("New task"); - expect(container.textContent).not.toContain("New sub-task"); + expect(container.textContent).toContain("New issue"); + expect(container.textContent).not.toContain("New sub-issue"); await waitForAssertion(() => { expect(container.textContent).toContain("Reusing PAP-100"); }); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Task")); + .find((button) => button.textContent?.includes("Create Issue")); expect(submitButton).not.toBeUndefined(); await act(async () => { @@ -578,7 +578,7 @@ describe("NewIssueDialog", () => { const { root } = renderDialog(container); await flush(); - const titleInput = container.querySelector('textarea[placeholder="Task title"]') as HTMLTextAreaElement | null; + const titleInput = container.querySelector('textarea[placeholder="Issue title"]') as HTMLTextAreaElement | null; const descriptionInput = container.querySelector('textarea[aria-label="Add description..."]') as HTMLTextAreaElement | null; expect(titleInput).not.toBeNull(); expect(descriptionInput).not.toBeNull(); @@ -601,7 +601,7 @@ describe("NewIssueDialog", () => { await flush(); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Task")); + .find((button) => button.textContent?.includes("Create Issue")); expect(submitButton).not.toBeUndefined(); await vi.waitFor(() => { expect(submitButton?.hasAttribute("disabled")).toBe(false); @@ -635,7 +635,7 @@ describe("NewIssueDialog", () => { const { root } = renderDialog(container); await flush(); - const titleInput = container.querySelector('textarea[placeholder="Task title"]') as HTMLTextAreaElement | null; + const titleInput = container.querySelector('textarea[placeholder="Issue title"]') as HTMLTextAreaElement | null; const descriptionInput = container.querySelector('textarea[aria-label="Add description..."]') as HTMLTextAreaElement | null; expect(titleInput).not.toBeNull(); expect(descriptionInput).not.toBeNull(); @@ -644,7 +644,7 @@ describe("NewIssueDialog", () => { await typeTextareaValue(descriptionInput!, description); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Task")); + .find((button) => button.textContent?.includes("Create Issue")); expect(submitButton).not.toBeUndefined(); await vi.waitFor(() => { expect(submitButton?.hasAttribute("disabled")).toBe(false); @@ -671,7 +671,7 @@ describe("NewIssueDialog", () => { const { root } = renderDialog(container); await flush(); - const titleInput = container.querySelector('textarea[placeholder="Task title"]') as HTMLTextAreaElement | null; + const titleInput = container.querySelector('textarea[placeholder="Issue title"]') as HTMLTextAreaElement | null; expect(titleInput).not.toBeNull(); await typeTextareaValue(titleInput!, "Plan this first"); @@ -683,7 +683,7 @@ describe("NewIssueDialog", () => { await flush(); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Task")); + .find((button) => button.textContent?.includes("Create Issue")); expect(submitButton).not.toBeUndefined(); await vi.waitFor(() => { expect(submitButton?.hasAttribute("disabled")).toBe(false); @@ -720,7 +720,7 @@ describe("NewIssueDialog", () => { await flush(); const submitButton = Array.from(container.querySelectorAll("button")) - .find((button) => button.textContent?.includes("Create Sub-Task")); + .find((button) => button.textContent?.includes("Create Sub-Issue")); expect(submitButton).not.toBeUndefined(); await act(async () => { @@ -754,7 +754,7 @@ describe("NewIssueDialog", () => { expect(dialogContent?.getAttribute("style")).toContain("env(safe-area-inset-top)"); expect(dialogContent?.getAttribute("style")).toContain("env(safe-area-inset-bottom)"); - const titleInput = container.querySelector('textarea[placeholder="Task title"]'); + const titleInput = container.querySelector('textarea[placeholder="Issue title"]'); const descriptionInput = container.querySelector('textarea[aria-label="Add description..."]'); const bodyScrollRegion = Array.from(container.querySelectorAll("div")).find((element) => typeof element.className === "string" && element.className.includes("overscroll-contain"), @@ -862,7 +862,7 @@ describe("NewIssueDialog", () => { await flush(); await flush(); - expect(container.textContent).not.toContain("will no longer use the parent task workspace"); + expect(container.textContent).not.toContain("will no longer use the parent issue workspace"); const selects = Array.from(container.querySelectorAll("select")); const modeSelect = selects[0] as HTMLSelectElement | undefined; @@ -874,7 +874,7 @@ describe("NewIssueDialog", () => { }); await flush(); - expect(container.textContent).toContain("will no longer use the parent task workspace"); + expect(container.textContent).toContain("will no longer use the parent issue workspace"); expect(container.textContent).toContain("Parent workspace"); act(() => root.unmount()); diff --git a/ui/src/components/NewIssueDialog.tsx b/ui/src/components/NewIssueDialog.tsx index 4083f4881f1..8354e336e02 100644 --- a/ui/src/components/NewIssueDialog.tsx +++ b/ui/src/components/NewIssueDialog.tsx @@ -316,7 +316,7 @@ const IssueTitleTextarea = memo(function IssueTitleTextarea({ return (