diff --git a/ui/src/components/IssueFiltersPopover.test.tsx b/ui/src/components/IssueFiltersPopover.test.tsx index 69eb612fee5..796735a8eb6 100644 --- a/ui/src/components/IssueFiltersPopover.test.tsx +++ b/ui/src/components/IssueFiltersPopover.test.tsx @@ -65,7 +65,6 @@ describe("IssueFiltersPopover", () => { agents={[{ id: "agent-1", name: "Agent One" }]} projects={[{ id: "project-1", name: "Project One" }]} labels={[{ id: "label-1", name: "Bug", color: "#ff0000" }]} - workspaces={[{ id: "workspace-1", name: "Workspace One" }]} enableRoutineVisibilityFilter />, ); @@ -73,6 +72,8 @@ describe("IssueFiltersPopover", () => { const popoverContent = container.querySelector("[data-testid='popover-content']"); expect(popoverContent).not.toBeNull(); + expect(popoverContent?.querySelector('[data-filter-options="workspaces"]')).toBeNull(); + expect(popoverContent?.textContent).not.toContain("Workspace"); expect(popoverContent?.className).toContain("overflow-y-auto"); expect(popoverContent?.className).toContain("max-h-(--sz-calc-9)"); expect(popoverContent?.querySelectorAll(".overflow-y-auto").length).toBe(0); @@ -97,7 +98,6 @@ describe("IssueFiltersPopover", () => { agents={[{ id: "agent-1", name: "Agent One" }]} projects={[{ id: "project-1", name: "Project One" }]} labels={[{ id: "label-1", name: "Bug", color: "#ff0000" }]} - workspaces={[{ id: "workspace-1", name: "Workspace One" }]} enableRoutineVisibilityFilter />, ); diff --git a/ui/src/components/IssueFiltersPopover.tsx b/ui/src/components/IssueFiltersPopover.tsx index 05f717493e2..5546054e1f9 100644 --- a/ui/src/components/IssueFiltersPopover.tsx +++ b/ui/src/components/IssueFiltersPopover.tsx @@ -4,7 +4,7 @@ import { Badge } from "@/components/ui/badge"; import { Checkbox } from "@/components/ui/checkbox"; import { Input } from "@/components/ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { Bot, Check, Filter, HardDrive, Search, User, X } from "lucide-react"; +import { Bot, Check, Filter, Search, User, X } from "lucide-react"; import { PriorityIcon } from "./PriorityIcon"; import { SHOW_TASK_PRIORITY_UI } from "../lib/ui-flags"; import { StatusIcon } from "./StatusIcon"; @@ -43,11 +43,6 @@ type LabelOption = { color: string; }; -type WorkspaceOption = { - id: string; - name: string; -}; - type CreatorOption = { id: string; label: string; @@ -116,7 +111,6 @@ export function IssueFiltersPopover({ enableRoutineVisibilityFilter = false, buttonVariant = "ghost", iconOnly = false, - workspaces, creators, presentation = "legacy", inboxScopeFilters, @@ -132,7 +126,6 @@ export function IssueFiltersPopover({ enableRoutineVisibilityFilter?: boolean; buttonVariant?: "ghost" | "outline"; iconOnly?: boolean; - workspaces?: WorkspaceOption[]; creators?: CreatorOption[]; presentation?: "legacy" | "streamlined"; inboxScopeFilters?: InboxScopeFilters; @@ -142,7 +135,6 @@ export function IssueFiltersPopover({ const [assigneeSearch, setAssigneeSearch] = useState(""); const [projectSearch, setProjectSearch] = useState(""); const [labelSearch, setLabelSearch] = useState(""); - const [workspaceSearch, setWorkspaceSearch] = useState(""); const visibleAgents = useMemo( () => searchIssueFilterOptions(agents, assigneeSearch, (option) => option.name), [agents, assigneeSearch], @@ -155,10 +147,6 @@ export function IssueFiltersPopover({ () => searchIssueFilterOptions(labels, labelSearch, (option) => option.name), [labels, labelSearch], ); - const visibleWorkspaces = useMemo( - () => searchIssueFilterOptions(workspaces, workspaceSearch, (option) => option.name), - [workspaces, workspaceSearch], - ); const creatorOptions = creators ?? []; const creatorOptionById = useMemo( () => new Map(creatorOptions.map((option) => [option.id, option])), @@ -490,27 +478,6 @@ export function IssueFiltersPopover({ ) : null} - {workspaces && workspaces.length > 0 ? ( -
- Workspace - {streamlined && workspaces.length > SEARCHABLE_FILTER_THRESHOLD ? ( - - ) : null} -
- {(streamlined ? visibleWorkspaces : workspaces).map((workspace) => ( - - ))} -
-
- ) : null} - {enableExternalObjectFilters ? (
External object status diff --git a/ui/src/components/IssuesList.test.tsx b/ui/src/components/IssuesList.test.tsx index 72cdcf23ecd..f50a3332c04 100644 --- a/ui/src/components/IssuesList.test.tsx +++ b/ui/src/components/IssuesList.test.tsx @@ -1928,6 +1928,56 @@ describe("IssuesList", () => { }); }); + it("ignores a saved workspace filter when the page address has no workspace query", async () => { + localStorage.setItem( + taskCollectionPreferencesStorageKey({ + companyId: "company-1", + collectionKey: "paperclip:test-issues", + }), + JSON.stringify({ + version: 1, + companyId: "company-1", + collectionKey: "paperclip:test-issues", + viewState: { + workspaces: ["workspace-alpha"], + }, + columns: ["id"], + }), + ); + const alphaIssue = createIssue({ + id: "issue-alpha", + identifier: "PAP-40", + title: "Alpha issue", + executionWorkspaceId: "workspace-alpha", + }); + const betaIssue = createIssue({ + id: "issue-beta", + identifier: "PAP-41", + title: "Beta issue", + executionWorkspaceId: "workspace-beta", + }); + + const { root } = renderWithQueryClient( + undefined} + />, + container, + ); + + await waitForAssertion(() => { + expect(container.textContent).toContain("Alpha issue"); + expect(container.textContent).toContain("Beta issue"); + }); + + act(() => { + root.unmount(); + }); + }); + it("applies an initial workspace filter from the issues URL state", async () => { const alphaIssue = createIssue({ id: "issue-alpha", diff --git a/ui/src/components/IssuesList.tsx b/ui/src/components/IssuesList.tsx index da467d40fda..4603c567b9f 100644 --- a/ui/src/components/IssuesList.tsx +++ b/ui/src/components/IssuesList.tsx @@ -207,6 +207,9 @@ function normalizeIssueViewState(value: unknown): IssueViewState { ...defaultViewState, ...parsed, ...normalizeIssueFilterState(parsed), + // A saved workspace selection has no filter control. Drop it on load. + // `initialWorkspaces` from the page address is applied after this. + workspaces: [], sortField: ["status", "priority", "title", "created", "updated", "workflow"].includes(parsed.sortField ?? "") ? parsed.sortField as IssueSortField : defaultViewState.sortField, @@ -1043,16 +1046,6 @@ function StreamlinedIssuesList({ return map; }, [defaultProjectWorkspaceIds, executionWorkspaceById, projectWorkspaceById]); - const workspaceOptions = useMemo(() => { - const options = new Map(); - for (const [workspaceId, workspaceName] of workspaceNameMap) { - options.set(workspaceId, workspaceName); - } - return [...options.entries()] - .sort((a, b) => a[1].localeCompare(b[1])) - .map(([id, name]) => ({ id, name })); - }, [workspaceNameMap]); - const creatorOptions = useMemo(() => { const options = new Map(); const knownAgentIds = new Set(); @@ -1920,7 +1913,6 @@ function StreamlinedIssuesList({ enableExternalObjectFilters={externalObjectsEnabled} enableRoutineVisibilityFilter={enableRoutineVisibilityFilter} iconOnly - workspaces={isolatedWorkspacesEnabled ? workspaceOptions : undefined} presentation={rowPresentation === "task" ? "streamlined" : "legacy"} /> diff --git a/ui/src/components/LegacyIssuesList.tsx b/ui/src/components/LegacyIssuesList.tsx index 55cfbb48f6d..5cd5db5358a 100644 --- a/ui/src/components/LegacyIssuesList.tsx +++ b/ui/src/components/LegacyIssuesList.tsx @@ -198,6 +198,7 @@ function getViewState(key: string): IssueViewState { ...defaultViewState, ...parsed, ...normalizeIssueFilterState(parsed), + workspaces: [], boardCardDensity: normalizeBoardCardDensity(parsed.boardCardDensity), boardColdLaneMode: normalizeBoardColdLaneMode(parsed.boardColdLaneMode), boardColumnPageSize: normalizeBoardColumnPageSize(parsed.boardColumnPageSize), @@ -965,16 +966,6 @@ export function IssuesList({ return map; }, [defaultProjectWorkspaceIds, executionWorkspaceById, projectWorkspaceById]); - const workspaceOptions = useMemo(() => { - const options = new Map(); - for (const [workspaceId, workspaceName] of workspaceNameMap) { - options.set(workspaceId, workspaceName); - } - return [...options.entries()] - .sort((a, b) => a[1].localeCompare(b[1])) - .map(([id, name]) => ({ id, name })); - }, [workspaceNameMap]); - const creatorOptions = useMemo(() => { const options = new Map(); const knownAgentIds = new Set(); @@ -1814,7 +1805,6 @@ export function IssuesList({ enableExternalObjectFilters={externalObjectsEnabled} enableRoutineVisibilityFilter={enableRoutineVisibilityFilter} iconOnly - workspaces={isolatedWorkspacesEnabled ? workspaceOptions : undefined} /> {/* Sort (list view only) */} diff --git a/ui/src/lib/inbox.test.ts b/ui/src/lib/inbox.test.ts index 36b3baf8067..79d0afbf397 100644 --- a/ui/src/lib/inbox.test.ts +++ b/ui/src/lib/inbox.test.ts @@ -1159,7 +1159,7 @@ describe("inbox helpers", () => { creators: ["user:user-1"], labels: ["label-1"], projects: ["project-1"], - workspaces: ["workspace-1"], + workspaces: [], liveOnly: true, externalObjectStatuses: [], hideRoutineExecutions: false, @@ -1210,7 +1210,7 @@ describe("inbox helpers", () => { creators: ["user:user-1"], labels: [], projects: ["project-1"], - workspaces: ["workspace-1"], + workspaces: [], liveOnly: false, externalObjectStatuses: [], hideRoutineExecutions: false, diff --git a/ui/src/lib/inbox.ts b/ui/src/lib/inbox.ts index c95b015352c..368cc213a48 100644 --- a/ui/src/lib/inbox.ts +++ b/ui/src/lib/inbox.ts @@ -217,7 +217,10 @@ export function loadInboxFilterPreferences( return { allCategoryFilter: normalizeInboxCategoryFilter(parsed.allCategoryFilter), allApprovalFilter: normalizeInboxApprovalFilter(parsed.allApprovalFilter), - issueFilters: normalizeIssueFilterState(parsed.issueFilters), + issueFilters: { + ...normalizeIssueFilterState(parsed.issueFilters), + workspaces: [], + }, }; } catch { return { @@ -240,7 +243,10 @@ export function saveInboxFilterPreferences( JSON.stringify({ allCategoryFilter: normalizeInboxCategoryFilter(preferences.allCategoryFilter), allApprovalFilter: normalizeInboxApprovalFilter(preferences.allApprovalFilter), - issueFilters: normalizeIssueFilterState(preferences.issueFilters), + issueFilters: { + ...normalizeIssueFilterState(preferences.issueFilters), + workspaces: [], + }, }), ); } catch { diff --git a/ui/src/pages/Inbox.tsx b/ui/src/pages/Inbox.tsx index 37944e25d83..88ae042b349 100644 --- a/ui/src/pages/Inbox.tsx +++ b/ui/src/pages/Inbox.tsx @@ -221,7 +221,13 @@ function normalizeInboxCollectionViewState(value: unknown): StreamlinedInboxView ? category : "everything", allApprovalFilter: approval === "actionable" || approval === "resolved" ? approval : "all", - issueFilters: normalizeIssueFilterState(candidate.issueFilters), + issueFilters: { + ...normalizeIssueFilterState(candidate.issueFilters), + // The filter menu no longer offers Workspace. Drop a saved selection so + // it cannot keep hiding tasks. A task-link workspace query is applied + // by the task list after this load. + workspaces: [], + }, showDateGroupSeparators: candidate.showDateGroupSeparators !== false, }; } @@ -2482,7 +2488,6 @@ function StreamlinedInbox({ enableRoutineVisibilityFilter buttonVariant="outline" iconOnly - workspaces={isolatedWorkspacesEnabled ? executionWorkspaces.filter((w) => w.mode === "isolated_workspace").map((w) => ({ id: w.id, name: w.name })) : undefined} presentation={streamlinedUiEnabled ? "streamlined" : "legacy"} /> @@ -2588,7 +2593,6 @@ function StreamlinedInbox({ enableRoutineVisibilityFilter buttonVariant="outline" iconOnly - workspaces={isolatedWorkspacesEnabled ? executionWorkspaces.filter((w) => w.mode === "isolated_workspace").map((w) => ({ id: w.id, name: w.name })) : undefined} presentation={streamlinedUiEnabled ? "streamlined" : "legacy"} inboxScopeFilters={tab === "all" ? { category: allCategoryFilter, diff --git a/ui/src/pages/LegacyInbox.tsx b/ui/src/pages/LegacyInbox.tsx index 35196635373..21d1a885e15 100644 --- a/ui/src/pages/LegacyInbox.tsx +++ b/ui/src/pages/LegacyInbox.tsx @@ -2353,7 +2353,6 @@ export function Inbox() { enableRoutineVisibilityFilter buttonVariant="outline" iconOnly - workspaces={isolatedWorkspacesEnabled ? executionWorkspaces.filter((w) => w.mode === "isolated_workspace").map((w) => ({ id: w.id, name: w.name })) : undefined} /> @@ -2452,7 +2451,6 @@ export function Inbox() { enableRoutineVisibilityFilter buttonVariant="outline" iconOnly - workspaces={isolatedWorkspacesEnabled ? executionWorkspaces.filter((w) => w.mode === "isolated_workspace").map((w) => ({ id: w.id, name: w.name })) : undefined} /> diff --git a/ui/storybook/stories/external-objects.stories.tsx b/ui/storybook/stories/external-objects.stories.tsx index 00108d96e13..e0e91816dae 100644 --- a/ui/storybook/stories/external-objects.stories.tsx +++ b/ui/storybook/stories/external-objects.stories.tsx @@ -32,7 +32,6 @@ import { import type { IssueExternalObjectGroup } from "@/hooks/useIssueExternalObjects"; import { storybookAgents, - storybookExecutionWorkspaces, storybookIssueLabels, storybookIssues, storybookProjects, @@ -650,7 +649,6 @@ function FilterPopoverWithExternalChecked() { currentUserId="user-board" enableRoutineVisibilityFilter buttonVariant="outline" - workspaces={storybookExecutionWorkspaces.map((workspace) => ({ id: workspace.id, name: workspace.name }))} creators={[ { id: "user:user-board", label: "Riley Board", kind: "user", searchText: "board user human" }, ]} diff --git a/ui/storybook/stories/issue-management.stories.tsx b/ui/storybook/stories/issue-management.stories.tsx index 1939c5b3bfd..e1774d82d92 100644 --- a/ui/storybook/stories/issue-management.stories.tsx +++ b/ui/storybook/stories/issue-management.stories.tsx @@ -596,7 +596,6 @@ function OpenFiltersPopover() { currentUserId="user-board" enableRoutineVisibilityFilter buttonVariant="outline" - workspaces={storybookExecutionWorkspaces.map((workspace) => ({ id: workspace.id, name: workspace.name }))} creators={[ { id: "user:user-board", label: "Riley Board", kind: "user", searchText: "board user human" }, ...storybookAgents.map((agent) => ({