diff --git a/ui/src/lib/useTaskNoun.test.tsx b/ui/src/lib/useTaskNoun.test.tsx deleted file mode 100644 index 8057d1c0dad..00000000000 --- a/ui/src/lib/useTaskNoun.test.tsx +++ /dev/null @@ -1,96 +0,0 @@ -// @vitest-environment jsdom - -import { flushSync } from "react-dom"; -import { createRoot } from "react-dom/client"; -import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; -import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; -import { useTaskNoun, type TaskNoun } from "./useTaskNoun"; - -const mockInstanceSettingsApi = vi.hoisted(() => ({ - getExperimental: vi.fn(), -})); - -vi.mock("../api/instanceSettings", () => ({ - instanceSettingsApi: mockInstanceSettingsApi, -})); - -// eslint-disable-next-line @typescript-eslint/no-explicit-any -(globalThis as any).IS_REACT_ACT_ENVIRONMENT = true; - -async function act(callback: () => void | Promise) { - let result: void | Promise = undefined; - flushSync(() => { - result = callback(); - }); - await result; -} - -async function flushReact() { - await act(async () => { - await Promise.resolve(); - await new Promise((resolve) => window.setTimeout(resolve, 0)); - }); -} - -let captured: TaskNoun | null = null; - -function Harness() { - captured = useTaskNoun(); - return null; -} - -async function renderHook() { - const container = document.createElement("div"); - document.body.appendChild(container); - const root = createRoot(container); - const queryClient = new QueryClient({ defaultOptions: { queries: { retry: false } } }); - await act(async () => { - root.render( - - - , - ); - }); - await flushReact(); - return () => { - root.unmount(); - container.remove(); - }; -} - -describe("useTaskNoun", () => { - beforeEach(() => { - captured = null; - }); - - afterEach(() => { - vi.clearAllMocks(); - document.body.innerHTML = ""; - }); - - it("returns the Issue noun when the streamlined-nav flag is OFF (default)", async () => { - mockInstanceSettingsApi.getExperimental.mockResolvedValue({ - enableStreamlinedLeftNavigation: false, - }); - const cleanup = await renderHook(); - expect(captured).toEqual({ singular: "Issue", plural: "Issues" }); - cleanup(); - }); - - it("returns the Task noun when the streamlined-nav flag is ON", async () => { - mockInstanceSettingsApi.getExperimental.mockResolvedValue({ - enableStreamlinedLeftNavigation: true, - }); - const cleanup = await renderHook(); - expect(captured).toEqual({ singular: "Task", plural: "Tasks" }); - cleanup(); - }); - - it("falls back to the Issue noun before settings have loaded", async () => { - // Never resolves — simulates the in-flight state on first render. - mockInstanceSettingsApi.getExperimental.mockReturnValue(new Promise(() => {})); - const cleanup = await renderHook(); - expect(captured).toEqual({ singular: "Issue", plural: "Issues" }); - cleanup(); - }); -}); diff --git a/ui/src/lib/useTaskNoun.ts b/ui/src/lib/useTaskNoun.ts deleted file mode 100644 index 1cda416c686..00000000000 --- a/ui/src/lib/useTaskNoun.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { useQuery } from "@tanstack/react-query"; -import { instanceSettingsApi } from "../api/instanceSettings"; -import { queryKeys } from "./queryKeys"; - -export interface TaskNoun { - /** "Task" when the streamlined-nav flag is ON, "Issue" when OFF. */ - singular: string; - /** "Tasks" when the streamlined-nav flag is ON, "Issues" when OFF. */ - plural: string; -} - -const ISSUE_NOUN: TaskNoun = { singular: "Issue", plural: "Issues" }; -const TASK_NOUN: TaskNoun = { singular: "Task", plural: "Tasks" }; - -/** - * Returns the user-facing noun for a unit of work, gated on the - * `enableStreamlinedLeftNavigation` experimental flag (PAP-80 D1 → option A). - * - * Flag ON → { singular: "Task", plural: "Tasks" } - * Flag OFF → { singular: "Issue", plural: "Issues" } (default) - * - * Intended only for the high-visibility surfaces (sidebar/mobile nav labels, - * the New-Task button, the tasks-list title/breadcrumb). Deeper copy stays - * on the already-renamed "Task" wording. - */ -export function useTaskNoun(): TaskNoun { - const { data: experimentalSettings } = useQuery({ - queryKey: queryKeys.instance.experimentalSettings, - queryFn: () => instanceSettingsApi.getExperimental(), - }); - - return experimentalSettings?.enableStreamlinedLeftNavigation === true - ? TASK_NOUN - : ISSUE_NOUN; -} diff --git a/ui/src/pages/Issues.tsx b/ui/src/pages/Issues.tsx index 4abe44460d5..d0be7d1d55b 100644 --- a/ui/src/pages/Issues.tsx +++ b/ui/src/pages/Issues.tsx @@ -10,7 +10,6 @@ import { useBreadcrumbs } from "../context/BreadcrumbContext"; import { collectLiveIssueIds } from "../lib/liveIssueIds"; import { queryKeys } from "../lib/queryKeys"; import { createIssueDetailLocationState } from "../lib/issueDetailBreadcrumb"; -import { useTaskNoun } from "../lib/useTaskNoun"; import { EmptyState } from "../components/EmptyState"; import { IssuesList } from "../components/IssuesList"; import { CircleDot } from "lucide-react"; @@ -59,7 +58,6 @@ export function buildIssuesSearchUrl(currentHref: string, search: string): strin export function Issues() { const { selectedCompanyId } = useCompany(); const { setBreadcrumbs } = useBreadcrumbs(); - const taskNoun = useTaskNoun(); const location = useLocation(); const [searchParams] = useSearchParams(); const queryClient = useQueryClient(); @@ -110,16 +108,16 @@ export function Issues() { const issueLinkState = useMemo( () => createIssueDetailLocationState( - taskNoun.plural, + "Tasks", `${location.pathname}${location.search}${location.hash}`, "issues", ), - [taskNoun.plural, location.pathname, location.search, location.hash], + [location.pathname, location.search, location.hash], ); useEffect(() => { - setBreadcrumbs([{ label: taskNoun.plural }]); - }, [setBreadcrumbs, taskNoun.plural]); + setBreadcrumbs([{ label: "Tasks" }]); + }, [setBreadcrumbs]); const issuePageSize = workspaceIdFilter ? WORKSPACE_FILTER_ISSUE_LIMIT : ISSUES_PAGE_SIZE; @@ -190,7 +188,6 @@ export function Issues() { projects={projects} liveIssueIds={liveIssueIds} viewStateKey="paperclip:issues-view" - createIssueLabel={taskNoun.singular} issueLinkState={issueLinkState} initialAssignees={searchParams.get("assignee") ? [searchParams.get("assignee")!] : undefined} initialWorkspaces={initialWorkspaces.length > 0 ? initialWorkspaces : undefined}