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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
useInboxReportSignals,
useInboxReportsInfinite,
} from "@features/inbox/hooks/useInboxReports";
import { useSignalSourceConfigs } from "@features/inbox/hooks/useSignalSourceConfigs";
import { useInboxCloudTaskStore } from "@features/inbox/stores/inboxCloudTaskStore";
import { useInboxSignalsFilterStore } from "@features/inbox/stores/inboxSignalsFilterStore";
import { useInboxSignalsSidebarStore } from "@features/inbox/stores/inboxSignalsSidebarStore";
Expand All @@ -19,6 +20,7 @@ import {
INBOX_REFETCH_INTERVAL_MS,
} from "@features/inbox/utils/inboxConstants";
import { useDraftStore } from "@features/message-editor/stores/draftStore";
import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore";
import { useCreateTask } from "@features/tasks/hooks/useTasks";
import { useFeatureFlag } from "@hooks/useFeatureFlag";
import { useRepositoryIntegration } from "@hooks/useIntegrations";
Expand Down Expand Up @@ -116,6 +118,9 @@ export function InboxSignalsTab() {
const sortField = useInboxSignalsFilterStore((s) => s.sortField);
const sortDirection = useInboxSignalsFilterStore((s) => s.sortDirection);
const searchQuery = useInboxSignalsFilterStore((s) => s.searchQuery);
const { data: signalSourceConfigs } = useSignalSourceConfigs();
const hasSignalSources = signalSourceConfigs?.some((c) => c.enabled) ?? false;
const openSettings = useSettingsDialogStore((s) => s.open);

const windowFocused = useRendererWindowFocusStore((s) => s.focused);
const isInboxView = useNavigationStore((s) => s.view.type === "inbox");
Expand Down Expand Up @@ -307,6 +312,37 @@ export function InboxSignalsTab() {
}

if (allReports.length === 0) {
if (!hasSignalSources) {
return (
<Flex
direction="column"
align="center"
justify="center"
gap="5"
height="100%"
px="5"
style={{ maxWidth: 480, margin: "0 auto" }}
>
<Flex direction="column" gap="2" style={{ width: "100%" }}>
<Text
size="2"
weight="medium"
align="center"
style={{ color: "var(--gray-12)" }}
>
Enable Inbox
</Text>
<Text size="1" align="center" style={{ color: "var(--gray-11)" }}>
Inbox automatically analyzes your product data and prioritizes
actionable tasks. Choose which sources to enable for this project.
</Text>
</Flex>
<Button size="2" onClick={() => openSettings("signals")}>
Configure signal sources
</Button>
</Flex>
);
}
return <InboxWarmingUpState />;
}

Expand Down
46 changes: 2 additions & 44 deletions apps/code/src/renderer/features/inbox/components/InboxView.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,11 @@
import { useSettingsDialogStore } from "@features/settings/stores/settingsDialogStore";
import { useSetHeaderContent } from "@hooks/useSetHeaderContent";
import { EnvelopeSimpleIcon, GearSixIcon } from "@phosphor-icons/react";
import { Box, Button, Flex, Text } from "@radix-ui/themes";
import { Box, Flex, Text } from "@radix-ui/themes";
import { useMemo } from "react";
import { useSignalSourceConfigs } from "../hooks/useSignalSourceConfigs";
import { InboxSignalsTab } from "./InboxSignalsTab";

function SignalsNotConfiguredState() {
const openSettings = useSettingsDialogStore((s) => s.open);

return (
<Flex
direction="column"
align="center"
justify="center"
gap="5"
height="100%"
px="5"
style={{ maxWidth: 480, margin: "0 auto" }}
>
<Flex direction="column" gap="2" style={{ width: "100%" }}>
<Text
size="2"
weight="medium"
align="center"
style={{ color: "var(--gray-12)" }}
>
Enable Inbox
</Text>
<Text size="1" align="center" style={{ color: "var(--gray-11)" }}>
Inbox automatically analyzes your product data and prioritizes
actionable tasks. Choose which sources to enable for this project.
</Text>
</Flex>

<Button size="2" onClick={() => openSettings("signals")}>
Configure signal sources
</Button>
</Flex>
);
}

export function InboxView() {
const { data: configs, isLoading } = useSignalSourceConfigs();
const hasConfigs = configs?.some((c) => c.enabled) ?? false;
const openSettings = useSettingsDialogStore((s) => s.open);

const headerContent = useMemo(
Expand Down Expand Up @@ -75,11 +37,7 @@ export function InboxView() {

return (
<Box style={{ height: "100%" }}>
{isLoading ? null : hasConfigs ? (
<InboxSignalsTab />
) : (
<SignalsNotConfiguredState />
)}
<InboxSignalsTab />
</Box>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
FolderOpenIcon,
FolderSimple,
FunnelSimple as FunnelSimpleIcon,
User,
Users,
} from "@phosphor-icons/react";
import { Box, Flex, Popover, Text } from "@radix-ui/themes";
import { useWorkspace } from "@renderer/features/workspace/hooks/useWorkspace";
Expand Down Expand Up @@ -120,8 +122,10 @@ function TaskRow({
function TaskFilterMenu() {
const organizeMode = useSidebarStore((state) => state.organizeMode);
const sortMode = useSidebarStore((state) => state.sortMode);
const showAllUsers = useSidebarStore((state) => state.showAllUsers);
const setOrganizeMode = useSidebarStore((state) => state.setOrganizeMode);
const setSortMode = useSidebarStore((state) => state.setSortMode);
const setShowAllUsers = useSidebarStore((state) => state.setShowAllUsers);

const itemClassName =
"flex w-full items-center justify-between rounded-sm px-1 py-1 text-left text-[13px] text-gray-12 transition-colors hover:bg-gray-3";
Expand Down Expand Up @@ -223,6 +227,51 @@ function TaskFilterMenu() {
</button>
</Box>
</Box>

{import.meta.env.DEV && (
<>
<div className="my-0.25 border-gray-6 border-t" />

<Box>
<Text
size="1"
className="text-gray-10"
weight="medium"
style={{ paddingLeft: "1px" }}
>
Show
</Text>
<Box mt="1">
<button
type="button"
className={itemClassName}
onClick={() => setShowAllUsers(false)}
>
<span className="flex items-center gap-1 text-gray-12">
<User size={14} className="text-gray-12" />
<span>My tasks</span>
</span>
{!showAllUsers && (
<Check size={12} className="text-gray-12" />
)}
</button>
<button
type="button"
className={itemClassName}
onClick={() => setShowAllUsers(true)}
>
<span className="flex items-center gap-1 text-gray-12">
<Users size={14} className="text-gray-12" />
<span>All tasks</span>
</span>
{showAllUsers && (
<Check size={12} className="text-gray-12" />
)}
</button>
</Box>
</Box>
</>
)}
</Flex>
</Popover.Content>
</Popover.Root>
Expand Down
11 changes: 8 additions & 3 deletions apps/code/src/renderer/features/sidebar/hooks/useSidebarData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,17 +145,22 @@ function groupByRepository(
export function useSidebarData({
activeView,
}: UseSidebarDataProps): SidebarData {
const { data: rawTasks = [], isLoading: isLoadingTasks } = useTasks();
const showAllUsers = useSidebarStore((state) => state.showAllUsers);
const { data: rawTasks = [], isLoading: isLoadingTasks } = useTasks({
showAllUsers,
});
const { data: workspaces, isFetched: isWorkspacesFetched } = useWorkspaces();
const archivedTaskIds = useArchivedTaskIds();
const suspendedTaskIds = useSuspendedTaskIds();
const isLoading = isLoadingTasks || !isWorkspacesFetched;
const allTasks = useMemo(
() =>
rawTasks.filter(
(task) => !archivedTaskIds.has(task.id) && !!workspaces?.[task.id],
(task) =>
!archivedTaskIds.has(task.id) &&
(showAllUsers || !!workspaces?.[task.id]),
),
[rawTasks, archivedTaskIds, workspaces],
[rawTasks, archivedTaskIds, workspaces, showAllUsers],
);
const sessions = useSessions();
const { timestamps } = useTaskViewed();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface SidebarStoreState {
historyVisibleCount: number;
organizeMode: "by-project" | "chronological";
sortMode: "updated" | "created";
showAllUsers: boolean;
}

interface SidebarStoreActions {
Expand All @@ -27,6 +28,7 @@ interface SidebarStoreActions {
resetHistoryVisibleCount: () => void;
setOrganizeMode: (mode: SidebarStoreState["organizeMode"]) => void;
setSortMode: (mode: SidebarStoreState["sortMode"]) => void;
setShowAllUsers: (showAllUsers: boolean) => void;
}

type SidebarStore = SidebarStoreState & SidebarStoreActions;
Expand All @@ -43,6 +45,7 @@ export const useSidebarStore = create<SidebarStore>()(
historyVisibleCount: 25,
organizeMode: "by-project",
sortMode: "updated",
showAllUsers: false,
setOpen: (open) => set({ open, hasUserSetOpen: true }),
setOpenAuto: (open) =>
set((state) => (state.hasUserSetOpen ? state : { open })),
Expand Down Expand Up @@ -91,6 +94,7 @@ export const useSidebarStore = create<SidebarStore>()(
resetHistoryVisibleCount: () => set({ historyVisibleCount: 25 }),
setOrganizeMode: (organizeMode) => set({ organizeMode }),
setSortMode: (sortMode) => set({ sortMode }),
setShowAllUsers: (showAllUsers) => set({ showAllUsers }),
}),
{
name: "sidebar-storage",
Expand All @@ -103,6 +107,7 @@ export const useSidebarStore = create<SidebarStore>()(
historyVisibleCount: state.historyVisibleCount,
organizeMode: state.organizeMode,
sortMode: state.sortMode,
showAllUsers: state.showAllUsers,
}),
merge: (persisted, current) => {
const persistedState = persisted as {
Expand All @@ -114,6 +119,7 @@ export const useSidebarStore = create<SidebarStore>()(
historyVisibleCount?: number;
organizeMode?: SidebarStoreState["organizeMode"];
sortMode?: SidebarStoreState["sortMode"];
showAllUsers?: boolean;
};
return {
...current,
Expand All @@ -127,6 +133,7 @@ export const useSidebarStore = create<SidebarStore>()(
persistedState.historyVisibleCount ?? current.historyVisibleCount,
organizeMode: persistedState.organizeMode ?? current.organizeMode,
sortMode: persistedState.sortMode ?? current.sortMode,
showAllUsers: persistedState.showAllUsers ?? current.showAllUsers,
};
},
},
Expand Down
10 changes: 7 additions & 3 deletions apps/code/src/renderer/features/tasks/hooks/useTasks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,19 @@ const taskKeys = {
detail: (id: string) => [...taskKeys.details(), id] as const,
};

export function useTasks(filters?: { repository?: string }) {
export function useTasks(filters?: {
repository?: string;
showAllUsers?: boolean;
}) {
const { data: currentUser } = useMeQuery();
const createdBy = filters?.showAllUsers ? undefined : currentUser?.id;

return useAuthenticatedQuery(
taskKeys.list({ ...filters, createdBy: currentUser?.id }),
taskKeys.list({ ...filters, createdBy }),
(client) =>
client.getTasks({
repository: filters?.repository,
createdBy: currentUser?.id,
createdBy,
}) as unknown as Promise<Task[]>,
{ enabled: !!currentUser?.id, refetchInterval: TASK_LIST_POLL_INTERVAL_MS },
);
Expand Down
Loading