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 f660aea4b..d8e2fb710 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 4ddd4834d..8aa66d17d 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 3fca36207..141049b25 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 45203cc03..b87d80c2f 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 28d430adb..d3ec7c0ae 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 3d02a5338..100987023 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 8aa66d17d..b6489d0af 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 + )}