From a6d412b4fc9400f0033e10f16e3d339fd0d7f7fb Mon Sep 17 00:00:00 2001 From: PostHog Code Date: Thu, 30 Apr 2026 12:00:46 +0000 Subject: [PATCH 1/2] feat(tasks): add dev-only toggle for internal tasks in sidebar Mirrors the upstream PostHog/posthog#56943 toggle so the desktop app can surface internal tasks for local debugging. The toggle lives in the sidebar's task filter menu, only renders when import.meta.env.DEV is true, and bypasses the workspace-existence filter so server-side internal tasks (which won't have a local workspace) are visible. The backend already gates internal=true behind DEBUG, so this stays a no-op in production. Generated-By: PostHog Code Task-Id: 10e42168-e889-48c0-a19e-bf07d32c2b37 --- apps/code/src/renderer/api/posthogClient.ts | 7 ++++++- .../features/sidebar/components/TaskListView.tsx | 13 +++++++++++++ .../features/sidebar/hooks/useSidebarData.ts | 12 +++++++++++- .../features/sidebar/stores/sidebarStore.ts | 7 +++++++ .../src/renderer/features/tasks/hooks/useTasks.ts | 6 +++++- apps/code/src/shared/types.ts | 1 + 6 files changed, 43 insertions(+), 3 deletions(-) diff --git a/apps/code/src/renderer/api/posthogClient.ts b/apps/code/src/renderer/api/posthogClient.ts index f660aea4ba..d8e2fb710c 100644 --- a/apps/code/src/renderer/api/posthogClient.ts +++ b/apps/code/src/renderer/api/posthogClient.ts @@ -785,9 +785,10 @@ export class PostHogAPIClient { repository?: string; createdBy?: number; originProduct?: string; + internal?: boolean; }) { const teamId = await this.getTeamId(); - const params: Record = { + const params: Record = { limit: 500, }; @@ -803,6 +804,10 @@ export class PostHogAPIClient { params.origin_product = options.originProduct; } + if (options?.internal) { + params.internal = true; + } + const data = await this.api.get(`/api/projects/{project_id}/tasks/`, { path: { project_id: teamId.toString() }, query: params, diff --git a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx index 4ddd4834de..8aa66d17d7 100644 --- a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx +++ b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx @@ -131,9 +131,11 @@ function TaskFilterMenu() { const organizeMode = useSidebarStore((state) => state.organizeMode); const sortMode = useSidebarStore((state) => state.sortMode); const showAllUsers = useSidebarStore((state) => state.showAllUsers); + const showInternal = useSidebarStore((state) => state.showInternal); const setOrganizeMode = useSidebarStore((state) => state.setOrganizeMode); const setSortMode = useSidebarStore((state) => state.setSortMode); const setShowAllUsers = useSidebarStore((state) => state.setShowAllUsers); + const setShowInternal = useSidebarStore((state) => state.setShowInternal); return ( @@ -192,6 +194,17 @@ function TaskFilterMenu() { All tasks + + + + Internal tasks + setShowInternal(value === "show")} + > + Hide + Show + )} diff --git a/apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts b/apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts index 3fca36207c..141049b250 100644 --- a/apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts +++ b/apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts @@ -80,8 +80,10 @@ export function useSidebarData({ activeView, }: UseSidebarDataProps): SidebarData { const showAllUsers = useSidebarStore((state) => state.showAllUsers); + const showInternal = useSidebarStore((state) => state.showInternal); const { data: rawTasks = [], isFetched: isTasksFetched } = useTasks({ showAllUsers, + showInternal, }); const { data: workspaces, isFetched: isWorkspacesFetched } = useWorkspaces(); const archivedTaskIds = useArchivedTaskIds(); @@ -94,10 +96,18 @@ export function useSidebarData({ (task) => !archivedTaskIds.has(task.id) && (showAllUsers || + showInternal || !!workspaces?.[task.id] || provisioningTaskIds.has(task.id)), ), - [rawTasks, archivedTaskIds, workspaces, showAllUsers, provisioningTaskIds], + [ + rawTasks, + archivedTaskIds, + workspaces, + showAllUsers, + showInternal, + provisioningTaskIds, + ], ); const sessions = useSessions(); const { timestamps } = useTaskViewed(); diff --git a/apps/code/src/renderer/features/sidebar/stores/sidebarStore.ts b/apps/code/src/renderer/features/sidebar/stores/sidebarStore.ts index 45203cc03f..b87d80c2f5 100644 --- a/apps/code/src/renderer/features/sidebar/stores/sidebarStore.ts +++ b/apps/code/src/renderer/features/sidebar/stores/sidebarStore.ts @@ -13,6 +13,7 @@ interface SidebarStoreState { organizeMode: "by-project" | "chronological"; sortMode: "updated" | "created"; showAllUsers: boolean; + showInternal: boolean; } interface SidebarStoreActions { @@ -30,6 +31,7 @@ interface SidebarStoreActions { setOrganizeMode: (mode: SidebarStoreState["organizeMode"]) => void; setSortMode: (mode: SidebarStoreState["sortMode"]) => void; setShowAllUsers: (showAllUsers: boolean) => void; + setShowInternal: (showInternal: boolean) => void; } type SidebarStore = SidebarStoreState & SidebarStoreActions; @@ -47,6 +49,7 @@ export const useSidebarStore = create()( organizeMode: "by-project", sortMode: "updated", showAllUsers: false, + showInternal: false, setOpen: (open) => set({ open, hasUserSetOpen: true }), setOpenAuto: (open) => set((state) => (state.hasUserSetOpen ? state : { open })), @@ -96,6 +99,7 @@ export const useSidebarStore = create()( setOrganizeMode: (organizeMode) => set({ organizeMode }), setSortMode: (sortMode) => set({ sortMode }), setShowAllUsers: (showAllUsers) => set({ showAllUsers }), + setShowInternal: (showInternal) => set({ showInternal }), }), { name: "sidebar-storage", @@ -109,6 +113,7 @@ export const useSidebarStore = create()( organizeMode: state.organizeMode, sortMode: state.sortMode, showAllUsers: state.showAllUsers, + showInternal: state.showInternal, }), merge: (persisted, current) => { const persistedState = persisted as { @@ -121,6 +126,7 @@ export const useSidebarStore = create()( organizeMode?: SidebarStoreState["organizeMode"]; sortMode?: SidebarStoreState["sortMode"]; showAllUsers?: boolean; + showInternal?: boolean; }; return { ...current, @@ -138,6 +144,7 @@ export const useSidebarStore = create()( organizeMode: persistedState.organizeMode ?? current.organizeMode, sortMode: persistedState.sortMode ?? current.sortMode, showAllUsers: persistedState.showAllUsers ?? current.showAllUsers, + showInternal: persistedState.showInternal ?? current.showInternal, }; }, }, diff --git a/apps/code/src/renderer/features/tasks/hooks/useTasks.ts b/apps/code/src/renderer/features/tasks/hooks/useTasks.ts index 28d430adb1..d3ec7c0ae4 100644 --- a/apps/code/src/renderer/features/tasks/hooks/useTasks.ts +++ b/apps/code/src/renderer/features/tasks/hooks/useTasks.ts @@ -24,6 +24,7 @@ const taskKeys = { repository?: string; createdBy?: number; originProduct?: string; + internal?: boolean; }) => [...taskKeys.lists(), filters] as const, details: () => [...taskKeys.all, "detail"] as const, detail: (id: string) => [...taskKeys.details(), id] as const, @@ -32,16 +33,19 @@ const taskKeys = { export function useTasks(filters?: { repository?: string; showAllUsers?: boolean; + showInternal?: boolean; }) { const { data: currentUser } = useMeQuery(); const createdBy = filters?.showAllUsers ? undefined : currentUser?.id; + const internal = filters?.showInternal ? true : undefined; return useAuthenticatedQuery( - taskKeys.list({ repository: filters?.repository, createdBy }), + taskKeys.list({ repository: filters?.repository, createdBy, internal }), (client) => client.getTasks({ repository: filters?.repository, createdBy, + internal, }) as unknown as Promise, { enabled: !!currentUser?.id, refetchInterval: TASK_LIST_POLL_INTERVAL_MS }, ); diff --git a/apps/code/src/shared/types.ts b/apps/code/src/shared/types.ts index 3d02a53382..1009870235 100644 --- a/apps/code/src/shared/types.ts +++ b/apps/code/src/shared/types.ts @@ -48,6 +48,7 @@ export interface Task { github_integration?: number | null; json_schema?: Record | null; signal_report?: string | null; + internal?: boolean; latest_run?: TaskRun; } From 799a9c02b0ac714a36949ef20fc5f0652b4a8b7b Mon Sep 17 00:00:00 2001 From: Joshua Snyder Date: Thu, 30 Apr 2026 15:09:46 +0100 Subject: [PATCH 2/2] show for staff users --- .../sidebar/components/TaskListView.tsx | 21 ++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx index 8aa66d17d7..b6489d0aff 100644 --- a/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx +++ b/apps/code/src/renderer/features/sidebar/components/TaskListView.tsx @@ -2,6 +2,7 @@ import { PointerSensor } from "@dnd-kit/dom"; import type { DragDropEvents } from "@dnd-kit/react"; import { DragDropProvider } from "@dnd-kit/react"; import { useFolders } from "@features/folders/hooks/useFolders"; +import { useMeQuery } from "@hooks/useMeQuery"; import { FunnelSimple as FunnelSimpleIcon, GitBranch, @@ -136,6 +137,8 @@ function TaskFilterMenu() { const setSortMode = useSidebarStore((state) => state.setSortMode); const setShowAllUsers = useSidebarStore((state) => state.setShowAllUsers); const setShowInternal = useSidebarStore((state) => state.setShowInternal); + const { data: currentUser } = useMeQuery(); + const isStaff = currentUser?.is_staff === true; return ( @@ -194,16 +197,24 @@ function TaskFilterMenu() { All tasks + + )} + {isStaff && ( + <> - Internal tasks + Task visibility setShowInternal(value === "show")} + value={showInternal ? "internal" : "external"} + onValueChange={(value) => setShowInternal(value === "internal")} > - Hide - Show + + External + + + Internal + )}