"use client"; import { memo, useMemo } from "react"; import { useTranslation } from "react-i18next"; import { TaskSwitcherSkeleton } from "./task-switcher-group"; import { GroupSection, type GroupSectionProps, type TaskRowBaseProps } from "./task-switcher-tree"; import type { TaskSwitcherProps } from "./task-switcher-types"; export type { StepDef, TaskLinkHandler, TaskSwitcherItem, TaskSwitcherProps, } from "./task-switcher-types"; export { dispatchSidebarRowClick } from "./task-switcher-click"; function buildTaskRowProps(props: TaskSwitcherProps): TaskRowBaseProps { return { workflows: props.workflows, stepsByWorkflowId: props.stepsByWorkflowId, activeTaskId: props.activeTaskId, selectedTaskId: props.selectedTaskId, onSelectTask: props.onSelectTask, onEditTask: props.onEditTask, onRenameTask: props.onRenameTask, onArchiveTask: props.onArchiveTask, onCreateSubtask: props.onCreateSubtask, onDeleteTask: props.onDeleteTask, onDetachTask: props.onDetachTask, onLinkPullRequest: props.onLinkPullRequest, onLinkIssue: props.onLinkIssue, onLinkMergeRequest: props.onLinkMergeRequest, onLinkJiraTicket: props.onLinkJiraTicket, onLinkLinearIssue: props.onLinkLinearIssue, onLinkSentryIssue: props.onLinkSentryIssue, onMoveToStep: props.onMoveToStep, onTogglePin: props.onTogglePin, pinnedTaskIds: props.pinnedTaskIds, deletingTaskId: props.deletingTaskId, selectedTaskIds: props.selectedTaskIds, onToggleSelectTask: props.onToggleSelectTask, onSelectTaskRange: props.onSelectTaskRange, onBulkArchive: props.onBulkArchive, onBulkDelete: props.onBulkDelete, onBulkPin: props.onBulkPin, onBulkMove: props.onBulkMove, onClearSelection: props.onClearSelection, isMixedWorkflowSelection: props.isMixedWorkflowSelection, }; } function buildGroupSectionProps( props: TaskSwitcherProps, options: { group: GroupSectionProps["group"]; rowProps: TaskRowBaseProps; pinnedSet: Set; collapsedSet: Set; showHeader: boolean; }, ): GroupSectionProps { const { group, rowProps, pinnedSet, collapsedSet, showHeader } = options; return { group, subTasksByParentId: props.grouped.subTasksByParentId, rowProps, pinnedSet, isCollapsed: collapsedSet.has(group.key), onToggleCollapsed: () => props.onToggleGroup?.(group.key), collapsedSubtaskParentIds: props.collapsedSubtaskParentIds, onToggleSubtasks: props.onToggleSubtasks, showHeader, onReorderGroup: props.onReorderGroup, onReorderSubtasks: props.onReorderSubtasks, }; } function LoadErrorNotice({ error, onRetry, retryLabel, }: { error?: string | null; onRetry?: () => void; retryLabel?: string; }) { if (!error) return null; return (
{error} {onRetry && retryLabel && ( )}
); } export const TaskSwitcher = memo(function TaskSwitcher(props: TaskSwitcherProps) { const { t } = useTranslation("sidebar"); const { grouped, isLoading = false, loadError, onRetryLoad, retryLabel, totalTaskCount } = props; const pinnedSet = useMemo(() => new Set(props.pinnedTaskIds ?? []), [props.pinnedTaskIds]); if (isLoading) return ; const totalTasks = totalTaskCount ?? grouped.groups.reduce((sum, group) => sum + group.tasks.length, 0); const loadErrorNotice = ( ); if (totalTasks === 0) { return ( <> {loadErrorNotice}
{t("noTasksYet")}
); } const collapsedSet = new Set(props.collapsedGroupKeys ?? []); const showHeaders = grouped.groups.length > 1 || (grouped.groups.length === 1 && grouped.groups[0].key !== "__all__"); const rowProps = buildTaskRowProps(props); return (
{loadErrorNotice} {grouped.groups.map((group) => ( ))}
); });