Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/code/src/renderer/api/posthogClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -785,9 +785,10 @@ export class PostHogAPIClient {
repository?: string;
createdBy?: number;
originProduct?: string;
internal?: boolean;
}) {
const teamId = await this.getTeamId();
const params: Record<string, string | number> = {
const params: Record<string, string | number | boolean> = {
limit: 500,
};

Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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 (
<DropdownMenu>
Expand Down Expand Up @@ -194,6 +199,25 @@ function TaskFilterMenu() {
</DropdownMenuRadioGroup>
</>
)}

{isStaff && (
<>
<DropdownMenuSeparator />

<MenuLabel>Task visibility</MenuLabel>
<DropdownMenuRadioGroup
value={showInternal ? "internal" : "external"}
onValueChange={(value) => setShowInternal(value === "internal")}
>
<DropdownMenuRadioItem value="external">
External
</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="internal">
Internal
</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</>
)}
</DropdownMenuContent>
</DropdownMenu>
Comment on lines 199 to 222
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Toggle visible in production for staff users but silently non-functional

The existing "Show all users" toggle is gated by import.meta.env.DEV, but this new toggle uses isStaff. Staff users in production builds will see "Task visibility" in the filter menu; however, the backend only honours internal=true when settings.DEBUG is enabled, so the toggle silently does nothing in production. Consider aligning the guard with the existing pattern (import.meta.env.DEV) or adding an import.meta.env.DEV check alongside isStaff to avoid showing a non-functional control to production staff.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/sidebar/components/TaskListView.tsx
Line: 199-222

Comment:
**Toggle visible in production for staff users but silently non-functional**

The existing "Show all users" toggle is gated by `import.meta.env.DEV`, but this new toggle uses `isStaff`. Staff users in production builds will see "Task visibility" in the filter menu; however, the backend only honours `internal=true` when `settings.DEBUG` is enabled, so the toggle silently does nothing in production. Consider aligning the guard with the existing pattern (`import.meta.env.DEV`) or adding an `import.meta.env.DEV` check alongside `isStaff` to avoid showing a non-functional control to production staff.

How can I resolve this? If you propose a fix, please make it concise.

);
Expand Down
12 changes: 11 additions & 1 deletion apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ interface SidebarStoreState {
organizeMode: "by-project" | "chronological";
sortMode: "updated" | "created";
showAllUsers: boolean;
showInternal: boolean;
}

interface SidebarStoreActions {
Expand All @@ -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;
Expand All @@ -47,6 +49,7 @@ export const useSidebarStore = create<SidebarStore>()(
organizeMode: "by-project",
sortMode: "updated",
showAllUsers: false,
showInternal: false,
setOpen: (open) => set({ open, hasUserSetOpen: true }),
setOpenAuto: (open) =>
set((state) => (state.hasUserSetOpen ? state : { open })),
Expand Down Expand Up @@ -96,6 +99,7 @@ export const useSidebarStore = create<SidebarStore>()(
setOrganizeMode: (organizeMode) => set({ organizeMode }),
setSortMode: (sortMode) => set({ sortMode }),
setShowAllUsers: (showAllUsers) => set({ showAllUsers }),
setShowInternal: (showInternal) => set({ showInternal }),
}),
{
name: "sidebar-storage",
Expand All @@ -109,6 +113,7 @@ export const useSidebarStore = create<SidebarStore>()(
organizeMode: state.organizeMode,
sortMode: state.sortMode,
showAllUsers: state.showAllUsers,
showInternal: state.showInternal,
}),
merge: (persisted, current) => {
const persistedState = persisted as {
Expand All @@ -121,6 +126,7 @@ export const useSidebarStore = create<SidebarStore>()(
organizeMode?: SidebarStoreState["organizeMode"];
sortMode?: SidebarStoreState["sortMode"];
showAllUsers?: boolean;
showInternal?: boolean;
};
return {
...current,
Expand All @@ -138,6 +144,7 @@ export const useSidebarStore = create<SidebarStore>()(
organizeMode: persistedState.organizeMode ?? current.organizeMode,
sortMode: persistedState.sortMode ?? current.sortMode,
showAllUsers: persistedState.showAllUsers ?? current.showAllUsers,
showInternal: persistedState.showInternal ?? current.showInternal,
};
},
},
Expand Down
6 changes: 5 additions & 1 deletion apps/code/src/renderer/features/tasks/hooks/useTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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;
Comment on lines 39 to +40
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 createdBy not cleared when fetching internal tasks

When showInternal is true but showAllUsers is false, createdBy is still set to currentUser?.id. Internal tasks are created by the agent service (not the current user), so the backend receives both internal=true and created_by=<userId> — and applying both filters together will likely return an empty result set. createdBy should be undefined whenever showInternal is true.

Suggested change
const createdBy = filters?.showAllUsers ? undefined : currentUser?.id;
const internal = filters?.showInternal ? true : undefined;
const createdBy = filters?.showAllUsers || filters?.showInternal ? undefined : currentUser?.id;
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/renderer/features/tasks/hooks/useTasks.ts
Line: 39-40

Comment:
**`createdBy` not cleared when fetching internal tasks**

When `showInternal` is `true` but `showAllUsers` is `false`, `createdBy` is still set to `currentUser?.id`. Internal tasks are created by the agent service (not the current user), so the backend receives both `internal=true` and `created_by=<userId>` — and applying both filters together will likely return an empty result set. `createdBy` should be `undefined` whenever `showInternal` is `true`.

```suggestion
  const createdBy = filters?.showAllUsers || filters?.showInternal ? undefined : currentUser?.id;
```

How can I resolve this? If you propose a fix, please make it concise.


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<Task[]>,
{ enabled: !!currentUser?.id, refetchInterval: TASK_LIST_POLL_INTERVAL_MS },
);
Expand Down
1 change: 1 addition & 0 deletions apps/code/src/shared/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ export interface Task {
github_integration?: number | null;
json_schema?: Record<string, unknown> | null;
signal_report?: string | null;
internal?: boolean;
latest_run?: TaskRun;
}

Expand Down
Loading