From 28a3ce3215e69c69b72dad02f2efa08a437f2305 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 7 Jul 2026 17:30:11 -0400 Subject: [PATCH 1/4] feat(sidebar): filter tasks by workspace type Add a "Task type" section to the tasks sidebar filter menu with multi-select checkboxes for worktree, local, and cloud tasks. Classification uses Workspace.mode, falling back to the cloud run environment. Tasks with an unknown mode always stay visible. Generated-By: PostHog Code Task-Id: 19431e3f-90a3-4440-910d-33b5ce011955 --- packages/core/src/sidebar/buildSidebarData.ts | 26 ++++++++++ .../src/sidebar/filterByWorkspaceMode.test.ts | 52 +++++++++++++++++++ .../core/src/sidebar/sidebarData.types.ts | 2 + .../sidebar/components/TasksHeader.tsx | 24 +++++++++ .../ui/src/features/sidebar/sidebarStore.ts | 15 ++++++ .../ui/src/features/sidebar/useSidebarData.ts | 11 +++- 6 files changed, 128 insertions(+), 2 deletions(-) create mode 100644 packages/core/src/sidebar/filterByWorkspaceMode.test.ts diff --git a/packages/core/src/sidebar/buildSidebarData.ts b/packages/core/src/sidebar/buildSidebarData.ts index 43edfc52b2..39bb00e14e 100644 --- a/packages/core/src/sidebar/buildSidebarData.ts +++ b/packages/core/src/sidebar/buildSidebarData.ts @@ -1,3 +1,4 @@ +import type { WorkspaceMode } from "@posthog/shared"; import type { Task, TaskRunStatus } from "@posthog/shared/domain-types"; import { getRepositoryInfo } from "./groupTasks"; import type { TaskData } from "./sidebarData.types"; @@ -116,6 +117,7 @@ export interface TaskWorkspace { folderPath?: string | null; branchName?: string | null; linkedBranch?: string | null; + mode?: WorkspaceMode; } export interface TaskTimestamp { @@ -174,6 +176,9 @@ export function deriveTaskData( folderId: workspace?.folderId || undefined, taskRunStatus: session?.cloudStatus ?? task.latest_run?.status ?? undefined, taskRunEnvironment: task.latest_run?.environment ?? undefined, + workspaceMode: + workspace?.mode ?? + (task.latest_run?.environment === "cloud" ? "cloud" : undefined), originProduct, slackThreadUrl, folderPath: workspace?.folderPath ?? null, @@ -183,6 +188,27 @@ export function deriveTaskData( }; } +export const ALL_WORKSPACE_MODES: readonly WorkspaceMode[] = [ + "worktree", + "local", + "cloud", +]; + +/** + * Keeps tasks whose workspace mode is in `enabledModes`. Tasks without a known + * mode always pass so an unclassified task never silently disappears. + */ +export function filterByWorkspaceMode( + tasks: TaskData[], + enabledModes: readonly WorkspaceMode[], +): TaskData[] { + if (enabledModes.length >= ALL_WORKSPACE_MODES.length) return tasks; + return tasks.filter( + (task) => + task.workspaceMode == null || enabledModes.includes(task.workspaceMode), + ); +} + function getSortValue(task: TaskData, sortMode: SortMode): number { return sortMode === "updated" ? task.lastActivityAt : task.createdAt; } diff --git a/packages/core/src/sidebar/filterByWorkspaceMode.test.ts b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts new file mode 100644 index 0000000000..fe939d0c94 --- /dev/null +++ b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts @@ -0,0 +1,52 @@ +import { describe, expect, it } from "vitest"; +import { + ALL_WORKSPACE_MODES, + filterByWorkspaceMode, +} from "./buildSidebarData"; +import type { TaskData } from "./sidebarData.types"; + +const task = (overrides: Partial): TaskData => ({ + id: "t", + title: "t", + createdAt: 0, + lastActivityAt: 0, + isGenerating: false, + isUnread: false, + isPinned: false, + needsPermission: false, + repository: null, + isSuspended: false, + folderPath: null, + cloudPrUrl: null, + branchName: null, + linkedBranch: null, + ...overrides, +}); + +describe("filterByWorkspaceMode", () => { + const worktree = task({ id: "w", workspaceMode: "worktree" }); + const local = task({ id: "l", workspaceMode: "local" }); + const cloud = task({ id: "c", workspaceMode: "cloud" }); + const unknown = task({ id: "u", workspaceMode: undefined }); + const tasks = [worktree, local, cloud, unknown]; + + it("returns all tasks when every mode is enabled", () => { + expect(filterByWorkspaceMode(tasks, ALL_WORKSPACE_MODES)).toEqual(tasks); + }); + + it("keeps only tasks whose mode is enabled, plus unknown-mode tasks", () => { + expect(filterByWorkspaceMode(tasks, ["local"])).toEqual([local, unknown]); + }); + + it("keeps multiple enabled modes", () => { + expect(filterByWorkspaceMode(tasks, ["worktree", "cloud"])).toEqual([ + worktree, + cloud, + unknown, + ]); + }); + + it("keeps only unknown-mode tasks when nothing is enabled", () => { + expect(filterByWorkspaceMode(tasks, [])).toEqual([unknown]); + }); +}); diff --git a/packages/core/src/sidebar/sidebarData.types.ts b/packages/core/src/sidebar/sidebarData.types.ts index cf03c1fc6e..6efc20f4e3 100644 --- a/packages/core/src/sidebar/sidebarData.types.ts +++ b/packages/core/src/sidebar/sidebarData.types.ts @@ -1,3 +1,4 @@ +import type { WorkspaceMode } from "@posthog/shared"; import type { TaskRunStatus } from "@posthog/shared/domain-types"; import type { TaskGroup as GenericTaskGroup, @@ -18,6 +19,7 @@ export interface TaskData { folderId?: string; taskRunStatus?: TaskRunStatus; taskRunEnvironment?: "local" | "cloud"; + workspaceMode?: WorkspaceMode; originProduct?: string; slackThreadUrl?: string; folderPath: string | null; diff --git a/packages/ui/src/features/sidebar/components/TasksHeader.tsx b/packages/ui/src/features/sidebar/components/TasksHeader.tsx index ebb6f84e69..71466a7102 100644 --- a/packages/ui/src/features/sidebar/components/TasksHeader.tsx +++ b/packages/ui/src/features/sidebar/components/TasksHeader.tsx @@ -4,9 +4,11 @@ import { MagnifyingGlass, } from "@phosphor-icons/react"; import { useHostTRPCClient } from "@posthog/host-router/react"; +import type { WorkspaceMode } from "@posthog/shared"; import { Button, DropdownMenu, + DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuRadioGroup, DropdownMenuRadioItem, @@ -25,6 +27,12 @@ import { useState } from "react"; const log = logger.scope("tasks-header"); +const TASK_TYPE_OPTIONS: { value: WorkspaceMode; label: string }[] = [ + { value: "worktree", label: "Worktree" }, + { value: "local", label: "Local" }, + { value: "cloud", label: "Cloud" }, +]; + function AddFolderButton() { const trpcClient = useHostTRPCClient(); const { addFolder } = useFolders(); @@ -82,6 +90,8 @@ function TaskFilterMenu() { const setSortMode = useSidebarStore((state) => state.setSortMode); const setShowAllUsers = useSidebarStore((state) => state.setShowAllUsers); const setShowInternal = useSidebarStore((state) => state.setShowInternal); + const taskTypeFilter = useSidebarStore((state) => state.taskTypeFilter); + const toggleTaskType = useSidebarStore((state) => state.toggleTaskType); const { data: currentUser } = useMeQuery(); const isStaff = currentUser?.is_staff === true; @@ -126,6 +136,20 @@ function TaskFilterMenu() { Updated + + + Task type + {TASK_TYPE_OPTIONS.map((option) => ( + toggleTaskType(option.value)} + > + {option.label} + + ))} + {import.meta.env.DEV && ( <> diff --git a/packages/ui/src/features/sidebar/sidebarStore.ts b/packages/ui/src/features/sidebar/sidebarStore.ts index 37f18f4bd9..d2f5506094 100644 --- a/packages/ui/src/features/sidebar/sidebarStore.ts +++ b/packages/ui/src/features/sidebar/sidebarStore.ts @@ -1,3 +1,5 @@ +import { ALL_WORKSPACE_MODES } from "@posthog/core/sidebar/buildSidebarData"; +import type { WorkspaceMode } from "@posthog/shared"; import { create } from "zustand"; import { persist } from "zustand/middleware"; import { SIDEBAR_MIN_WIDTH } from "./constants"; @@ -14,6 +16,7 @@ interface SidebarStoreState { sortMode: "updated" | "created"; showAllUsers: boolean; showInternal: boolean; + taskTypeFilter: WorkspaceMode[]; } interface SidebarStoreActions { @@ -32,6 +35,7 @@ interface SidebarStoreActions { setSortMode: (mode: SidebarStoreState["sortMode"]) => void; setShowAllUsers: (showAllUsers: boolean) => void; setShowInternal: (showInternal: boolean) => void; + toggleTaskType: (mode: WorkspaceMode) => void; } type SidebarStore = SidebarStoreState & SidebarStoreActions; @@ -50,6 +54,7 @@ export const useSidebarStore = create()( sortMode: "updated", showAllUsers: false, showInternal: false, + taskTypeFilter: [...ALL_WORKSPACE_MODES], setOpen: (open) => set({ open, hasUserSetOpen: true }), setOpenAuto: (open) => set((state) => (state.hasUserSetOpen ? state : { open })), @@ -100,6 +105,12 @@ export const useSidebarStore = create()( setSortMode: (sortMode) => set({ sortMode }), setShowAllUsers: (showAllUsers) => set({ showAllUsers }), setShowInternal: (showInternal) => set({ showInternal }), + toggleTaskType: (mode) => + set((state) => ({ + taskTypeFilter: state.taskTypeFilter.includes(mode) + ? state.taskTypeFilter.filter((m) => m !== mode) + : [...state.taskTypeFilter, mode], + })), }), { name: "sidebar-storage", @@ -114,6 +125,7 @@ export const useSidebarStore = create()( sortMode: state.sortMode, showAllUsers: state.showAllUsers, showInternal: state.showInternal, + taskTypeFilter: state.taskTypeFilter, }), merge: (persisted, current) => { const persistedState = persisted as { @@ -127,6 +139,7 @@ export const useSidebarStore = create()( sortMode?: SidebarStoreState["sortMode"]; showAllUsers?: boolean; showInternal?: boolean; + taskTypeFilter?: WorkspaceMode[]; }; return { ...current, @@ -145,6 +158,8 @@ export const useSidebarStore = create()( sortMode: persistedState.sortMode ?? current.sortMode, showAllUsers: persistedState.showAllUsers ?? current.showAllUsers, showInternal: persistedState.showInternal ?? current.showInternal, + taskTypeFilter: + persistedState.taskTypeFilter ?? current.taskTypeFilter, }; }, }, diff --git a/packages/ui/src/features/sidebar/useSidebarData.ts b/packages/ui/src/features/sidebar/useSidebarData.ts index c05be96909..5e44b9e653 100644 --- a/packages/ui/src/features/sidebar/useSidebarData.ts +++ b/packages/ui/src/features/sidebar/useSidebarData.ts @@ -1,5 +1,6 @@ import { deriveTaskData, + filterByWorkspaceMode, type FullTask, filterVisibleTasks, narrowFullTask, @@ -51,6 +52,7 @@ export function useSidebarData({ const organizeMode = useSidebarStore((state) => state.organizeMode); const sortMode = useSidebarStore((state) => state.sortMode); const folderOrder = useSidebarStore((state) => state.folderOrder); + const taskTypeFilter = useSidebarStore((state) => state.taskTypeFilter); const summaryIds = useMemo( () => @@ -166,9 +168,14 @@ export function useSidebarData({ ], ); + const filteredTaskData = useMemo( + () => filterByWorkspaceMode(taskData, taskTypeFilter), + [taskData, taskTypeFilter], + ); + const { pinnedTasks, sortedUnpinnedTasks, totalCount } = useMemo( - () => partitionAndSortTasks(taskData, sortMode), - [taskData, sortMode], + () => partitionAndSortTasks(filteredTaskData, sortMode), + [filteredTaskData, sortMode], ); const { flatTasks, hasMore } = useMemo( From 7e1d85518948ebc73565a0432feabddcb660dfb7 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Tue, 7 Jul 2026 17:46:25 -0400 Subject: [PATCH 2/4] style(sidebar): fix biome import sorting and formatting Generated-By: PostHog Code Task-Id: 19431e3f-90a3-4440-910d-33b5ce011955 --- packages/core/src/sidebar/filterByWorkspaceMode.test.ts | 5 +---- packages/ui/src/features/sidebar/components/TasksHeader.tsx | 2 +- packages/ui/src/features/sidebar/useSidebarData.ts | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/packages/core/src/sidebar/filterByWorkspaceMode.test.ts b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts index fe939d0c94..4089df17e7 100644 --- a/packages/core/src/sidebar/filterByWorkspaceMode.test.ts +++ b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts @@ -1,8 +1,5 @@ import { describe, expect, it } from "vitest"; -import { - ALL_WORKSPACE_MODES, - filterByWorkspaceMode, -} from "./buildSidebarData"; +import { ALL_WORKSPACE_MODES, filterByWorkspaceMode } from "./buildSidebarData"; import type { TaskData } from "./sidebarData.types"; const task = (overrides: Partial): TaskData => ({ diff --git a/packages/ui/src/features/sidebar/components/TasksHeader.tsx b/packages/ui/src/features/sidebar/components/TasksHeader.tsx index 71466a7102..5fd6726311 100644 --- a/packages/ui/src/features/sidebar/components/TasksHeader.tsx +++ b/packages/ui/src/features/sidebar/components/TasksHeader.tsx @@ -4,7 +4,6 @@ import { MagnifyingGlass, } from "@phosphor-icons/react"; import { useHostTRPCClient } from "@posthog/host-router/react"; -import type { WorkspaceMode } from "@posthog/shared"; import { Button, DropdownMenu, @@ -16,6 +15,7 @@ import { DropdownMenuTrigger, MenuLabel, } from "@posthog/quill"; +import type { WorkspaceMode } from "@posthog/shared"; import { useMeQuery } from "@posthog/ui/features/auth/useMeQuery"; import { useFolders } from "@posthog/ui/features/folders/useFolders"; import { useSidebarStore } from "@posthog/ui/features/sidebar/sidebarStore"; diff --git a/packages/ui/src/features/sidebar/useSidebarData.ts b/packages/ui/src/features/sidebar/useSidebarData.ts index 5e44b9e653..0340ccd69f 100644 --- a/packages/ui/src/features/sidebar/useSidebarData.ts +++ b/packages/ui/src/features/sidebar/useSidebarData.ts @@ -1,7 +1,7 @@ import { deriveTaskData, - filterByWorkspaceMode, type FullTask, + filterByWorkspaceMode, filterVisibleTasks, narrowFullTask, partitionAndSortTasks, From 04e75df204662b49a06bad360449ed420e896e1b Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Wed, 8 Jul 2026 11:17:41 -0400 Subject: [PATCH 3/4] refactor(sidebar): derive workspace-mode lists from a single exhaustive source Address review feedback: make ALL_WORKSPACE_MODES and the filter menu's TASK_TYPE_OPTIONS derive from Record so adding a mode to the schema forces a compile error instead of silently drifting. Parameterize the filterByWorkspaceMode tests with it.each. Add a comment clarifying that the latest_run cloud fallback mostly only matters in the showAllUsers view. Generated-By: PostHog Code Task-Id: 19431e3f-90a3-4440-910d-33b5ce011955 --- packages/core/src/sidebar/buildSidebarData.ts | 20 ++++++-- .../src/sidebar/filterByWorkspaceMode.test.ts | 46 +++++++++++-------- .../sidebar/components/TasksHeader.tsx | 19 ++++++-- 3 files changed, 57 insertions(+), 28 deletions(-) diff --git a/packages/core/src/sidebar/buildSidebarData.ts b/packages/core/src/sidebar/buildSidebarData.ts index 39bb00e14e..b70ce0f956 100644 --- a/packages/core/src/sidebar/buildSidebarData.ts +++ b/packages/core/src/sidebar/buildSidebarData.ts @@ -176,6 +176,9 @@ export function deriveTaskData( folderId: workspace?.folderId || undefined, taskRunStatus: session?.cloudStatus ?? task.latest_run?.status ?? undefined, taskRunEnvironment: task.latest_run?.environment ?? undefined, + // The `latest_run` fallback only matters in the `showAllUsers` view: the + // default view's `filterVisibleTasks` already restricts to tasks with a + // local `workspace`, so a pure-cloud task without one only shows up there. workspaceMode: workspace?.mode ?? (task.latest_run?.environment === "cloud" ? "cloud" : undefined), @@ -188,11 +191,18 @@ export function deriveTaskData( }; } -export const ALL_WORKSPACE_MODES: readonly WorkspaceMode[] = [ - "worktree", - "local", - "cloud", -]; +// A Record keyed by the full `WorkspaceMode` union, so adding a mode to the +// schema forces a compile error here instead of silently falling out of sync +// with `ALL_WORKSPACE_MODES` (and the filter's "all enabled" short-circuit). +const WORKSPACE_MODE_MEMBERSHIP: Record = { + worktree: true, + local: true, + cloud: true, +}; + +export const ALL_WORKSPACE_MODES: readonly WorkspaceMode[] = Object.keys( + WORKSPACE_MODE_MEMBERSHIP, +) as WorkspaceMode[]; /** * Keeps tasks whose workspace mode is in `enabledModes`. Tasks without a known diff --git a/packages/core/src/sidebar/filterByWorkspaceMode.test.ts b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts index 4089df17e7..e678f5840f 100644 --- a/packages/core/src/sidebar/filterByWorkspaceMode.test.ts +++ b/packages/core/src/sidebar/filterByWorkspaceMode.test.ts @@ -1,3 +1,4 @@ +import type { WorkspaceMode } from "@posthog/shared"; import { describe, expect, it } from "vitest"; import { ALL_WORKSPACE_MODES, filterByWorkspaceMode } from "./buildSidebarData"; import type { TaskData } from "./sidebarData.types"; @@ -27,23 +28,32 @@ describe("filterByWorkspaceMode", () => { const unknown = task({ id: "u", workspaceMode: undefined }); const tasks = [worktree, local, cloud, unknown]; - it("returns all tasks when every mode is enabled", () => { - expect(filterByWorkspaceMode(tasks, ALL_WORKSPACE_MODES)).toEqual(tasks); - }); - - it("keeps only tasks whose mode is enabled, plus unknown-mode tasks", () => { - expect(filterByWorkspaceMode(tasks, ["local"])).toEqual([local, unknown]); - }); - - it("keeps multiple enabled modes", () => { - expect(filterByWorkspaceMode(tasks, ["worktree", "cloud"])).toEqual([ - worktree, - cloud, - unknown, - ]); - }); - - it("keeps only unknown-mode tasks when nothing is enabled", () => { - expect(filterByWorkspaceMode(tasks, [])).toEqual([unknown]); + it.each<{ + name: string; + enabledModes: readonly WorkspaceMode[]; + expected: TaskData[]; + }>([ + { + name: "returns all tasks when every mode is enabled", + enabledModes: ALL_WORKSPACE_MODES, + expected: tasks, + }, + { + name: "keeps only tasks whose mode is enabled, plus unknown-mode tasks", + enabledModes: ["local"], + expected: [local, unknown], + }, + { + name: "keeps multiple enabled modes", + enabledModes: ["worktree", "cloud"], + expected: [worktree, cloud, unknown], + }, + { + name: "keeps only unknown-mode tasks when nothing is enabled", + enabledModes: [], + expected: [unknown], + }, + ])("$name", ({ enabledModes, expected }) => { + expect(filterByWorkspaceMode(tasks, enabledModes)).toEqual(expected); }); }); diff --git a/packages/ui/src/features/sidebar/components/TasksHeader.tsx b/packages/ui/src/features/sidebar/components/TasksHeader.tsx index 5fd6726311..a2784065d2 100644 --- a/packages/ui/src/features/sidebar/components/TasksHeader.tsx +++ b/packages/ui/src/features/sidebar/components/TasksHeader.tsx @@ -3,6 +3,7 @@ import { FunnelSimple as FunnelSimpleIcon, MagnifyingGlass, } from "@phosphor-icons/react"; +import { ALL_WORKSPACE_MODES } from "@posthog/core/sidebar/buildSidebarData"; import { useHostTRPCClient } from "@posthog/host-router/react"; import { Button, @@ -27,11 +28,19 @@ import { useState } from "react"; const log = logger.scope("tasks-header"); -const TASK_TYPE_OPTIONS: { value: WorkspaceMode; label: string }[] = [ - { value: "worktree", label: "Worktree" }, - { value: "local", label: "Local" }, - { value: "cloud", label: "Cloud" }, -]; +// Record (not a hand-maintained array) so adding a WorkspaceMode forces a +// compile error here instead of silently missing a checkbox. +const TASK_TYPE_LABELS: Record = { + worktree: "Worktree", + local: "Local", + cloud: "Cloud", +}; + +const TASK_TYPE_OPTIONS: { value: WorkspaceMode; label: string }[] = + ALL_WORKSPACE_MODES.map((mode) => ({ + value: mode, + label: TASK_TYPE_LABELS[mode], + })); function AddFolderButton() { const trpcClient = useHostTRPCClient(); From 601878e61b463e2b02f19e080848c29a3129cda8 Mon Sep 17 00:00:00 2001 From: Matt Pua Date: Wed, 8 Jul 2026 12:14:07 -0400 Subject: [PATCH 4/4] feat(sidebar): move task-type filter into an Environment submenu Group the worktree/local/cloud checkboxes under an "Environment" submenu with per-mode icons, positioned at the bottom of the filter menu. Generated-By: PostHog Code Task-Id: 9bca5aa3-3b30-4dfe-a09c-cc2a2832f979 --- .../sidebar/components/TasksHeader.tsx | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/ui/src/features/sidebar/components/TasksHeader.tsx b/packages/ui/src/features/sidebar/components/TasksHeader.tsx index a2784065d2..ebe4066a59 100644 --- a/packages/ui/src/features/sidebar/components/TasksHeader.tsx +++ b/packages/ui/src/features/sidebar/components/TasksHeader.tsx @@ -1,6 +1,10 @@ import { + Cloud, + Desktop, FolderPlus, FunnelSimple as FunnelSimpleIcon, + GitBranch, + type Icon, MagnifyingGlass, } from "@phosphor-icons/react"; import { ALL_WORKSPACE_MODES } from "@posthog/core/sidebar/buildSidebarData"; @@ -13,6 +17,9 @@ import { DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, DropdownMenuTrigger, MenuLabel, } from "@posthog/quill"; @@ -30,18 +37,12 @@ const log = logger.scope("tasks-header"); // Record (not a hand-maintained array) so adding a WorkspaceMode forces a // compile error here instead of silently missing a checkbox. -const TASK_TYPE_LABELS: Record = { - worktree: "Worktree", - local: "Local", - cloud: "Cloud", +const ENVIRONMENT_META: Record = { + worktree: { label: "Worktree", icon: GitBranch }, + local: { label: "Local", icon: Desktop }, + cloud: { label: "Cloud", icon: Cloud }, }; -const TASK_TYPE_OPTIONS: { value: WorkspaceMode; label: string }[] = - ALL_WORKSPACE_MODES.map((mode) => ({ - value: mode, - label: TASK_TYPE_LABELS[mode], - })); - function AddFolderButton() { const trpcClient = useHostTRPCClient(); const { addFolder } = useFolders(); @@ -145,20 +146,6 @@ function TaskFilterMenu() { Updated - - - Task type - {TASK_TYPE_OPTIONS.map((option) => ( - toggleTaskType(option.value)} - > - {option.label} - - ))} - {import.meta.env.DEV && ( <> @@ -196,6 +183,28 @@ function TaskFilterMenu() { )} + + + + + Environment + + {ALL_WORKSPACE_MODES.map((mode) => { + const { label, icon: Icon } = ENVIRONMENT_META[mode]; + return ( + toggleTaskType(mode)} + > + + {label} + + ); + })} + + );