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..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, @@ -131,9 +132,13 @@ 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); + const { data: currentUser } = useMeQuery(); + const isStaff = currentUser?.is_staff === true; return ( @@ -194,6 +199,25 @@ function TaskFilterMenu() { )} + + {isStaff && ( + <> + + + Task visibility + setShowInternal(value === "internal")} + > + + External + + + Internal + + + + )} ); 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; }