45cef11630
Architecture Lint / Architecture boundaries do not regress (push) Has been cancelled
Backend Tests / Plan external runner allocation (push) Has been cancelled
Backend Tests / Detect relevant changes (push) Has been cancelled
E2E Tests / Plan external runner allocation (push) Has been cancelled
Frontend Tests / Plan external runner allocation (push) Has been cancelled
Lint Action Pinning / All action refs are SHA-pinned (push) Has been cancelled
Lint Harness Files / Harness files pass lint (push) Has been cancelled
Backend Tests / Backend Static Checks (push) Has been cancelled
Backend Tests / Backend Tests (1/2) (push) Has been cancelled
Backend Tests / Backend Tests (2/2) (push) Has been cancelled
Backend Tests / Backend (ambient integration env) (push) Has been cancelled
Backend Tests / Run Backend Tests (push) Has been cancelled
Backend Tests / Backend Postgres (push) Has been cancelled
Backend Tests / Backend Postgres 18 (push) Has been cancelled
Backend Tests / Backend (windows) (push) Has been cancelled
E2E Tests / Detect relevant changes (push) Has been cancelled
E2E Tests / Build (push) Has been cancelled
E2E Tests / E2E Shard ${{ matrix.shard }}/14 (push) Has been cancelled
E2E Tests / Resolve Playwright runtime image (push) Has been cancelled
E2E Tests / E2E Containers Shard 1/6 (push) Has been cancelled
E2E Tests / E2E Containers Shard 2/6 (push) Has been cancelled
E2E Tests / E2E Containers Shard 3/6 (push) Has been cancelled
E2E Tests / E2E Containers Shard 4/6 (push) Has been cancelled
E2E Tests / E2E Containers Shard 5/6 (push) Has been cancelled
E2E Tests / E2E Containers Shard 6/6 (push) Has been cancelled
E2E Tests / Kubernetes Compatibility (v1.34.8) (push) Has been cancelled
E2E Tests / Kubernetes Compatibility (v1.36.1) (push) Has been cancelled
E2E Tests / Desktop E2E Smoke (push) Has been cancelled
E2E Tests / Merge E2E Reports (push) Has been cancelled
E2E Tests / E2E Tests Passed (push) Has been cancelled
Frontend Tests / Detect relevant changes (push) Has been cancelled
Frontend Tests / Run Frontend Lint, Tests, and Build (push) Has been cancelled
Frontend Tests / Frontend Tests Passed (push) Has been cancelled
143 lines
5.5 KiB
TypeScript
143 lines
5.5 KiB
TypeScript
import {
|
|
repositoryId as toRepositoryId,
|
|
type Repository,
|
|
type TaskSessionState,
|
|
type TaskState,
|
|
} from "@/lib/types/http";
|
|
import type { KanbanState } from "@/lib/state/slices";
|
|
import { statusSummaryActiveErrorPreview } from "@/lib/task-status-summary";
|
|
import type { WipQueueStatus } from "@/lib/kanban/wip-queue";
|
|
import { resolveTaskRepositorySlugs } from "@/lib/sidebar/sidebar-task-repositories";
|
|
import { effectiveTaskPendingAction } from "../task-select-helpers";
|
|
import { taskPRInfoFromSummary } from "../task-pr-info";
|
|
import type { SidebarTaskColorAutomation } from "@/lib/task-color-automation-settings";
|
|
import { taskColorFacts } from "@/lib/sidebar/task-color-projection";
|
|
import { resolveAutomaticTaskColor } from "@/lib/sidebar/task-color-rules";
|
|
|
|
export type SheetItemCtx = {
|
|
repositoryPathsById: Map<string, string | undefined>;
|
|
workflowNameById: Map<string, string>;
|
|
stepTitleById: Map<string, string>;
|
|
wipQueueByTaskId?: Map<string, WipQueueStatus>;
|
|
acknowledgedAgentErrors?: Record<string, string>;
|
|
dismissedAgentErrors?: Record<string, string>;
|
|
workspaceId?: string;
|
|
repositoriesById?: ReadonlyMap<string, Repository>;
|
|
stepColorById?: ReadonlyMap<string, string>;
|
|
automaticColorSettings?: SidebarTaskColorAutomation;
|
|
pendingArchiveTaskIds?: ReadonlySet<string>;
|
|
};
|
|
|
|
const EMPTY_REPOSITORIES_BY_ID = new Map<string, Repository>();
|
|
const EMPTY_STEP_COLORS = new Map<string, string>();
|
|
|
|
function sheetDiffStats(summary: KanbanState["tasks"][number]["statusSummary"]) {
|
|
const git = summary?.git;
|
|
if (!git || ((git.additions ?? 0) <= 0 && (git.deletions ?? 0) <= 0)) return undefined;
|
|
return { additions: git.additions ?? 0, deletions: git.deletions ?? 0 };
|
|
}
|
|
|
|
function sheetRepositoryPath(
|
|
task: KanbanState["tasks"][number],
|
|
ctx: SheetItemCtx,
|
|
): string | undefined {
|
|
return task.repositoryId
|
|
? ctx.repositoryPathsById.get(toRepositoryId(task.repositoryId))
|
|
: undefined;
|
|
}
|
|
|
|
function sheetPendingFlags(task: KanbanState["tasks"][number]) {
|
|
const action = effectiveTaskPendingAction(task);
|
|
return {
|
|
clarification: action === "clarification",
|
|
permission: action === "permission",
|
|
};
|
|
}
|
|
|
|
function sheetLaunchQueue(task: KanbanState["tasks"][number]) {
|
|
return task.statusSummary?.launch_queue;
|
|
}
|
|
|
|
function sheetLastActivity(task: KanbanState["tasks"][number]) {
|
|
return task.statusSummary?.last_activity_at ?? task.updatedAt ?? task.createdAt;
|
|
}
|
|
|
|
function sheetStatus(task: KanbanState["tasks"][number], ctx: SheetItemCtx) {
|
|
const summary = task.statusSummary;
|
|
const hasSummary = summary != null;
|
|
const pending = sheetPendingFlags(task);
|
|
return {
|
|
sessionState: hasSummary
|
|
? summary?.primary_session?.state
|
|
: (task.primarySessionState as TaskSessionState | undefined),
|
|
foregroundActivity: hasSummary ? summary?.foreground_activity : task.foregroundActivity,
|
|
repositoryPath: sheetRepositoryPath(task, ctx),
|
|
repositories: resolveTaskRepositorySlugs(task.repositories, ctx.repositoryPathsById),
|
|
diffStats: sheetDiffStats(summary),
|
|
comparisonUnavailable: summary?.git?.comparison_unavailable === true,
|
|
updatedAt: hasSummary ? summary?.updated_at : task.updatedAt,
|
|
primarySessionId: hasSummary
|
|
? (summary?.primary_session?.id ?? null)
|
|
: (task.primarySessionId ?? null),
|
|
hasPendingClarification: pending.clarification,
|
|
hasPendingPermission: pending.permission,
|
|
prInfo: taskPRInfoFromSummary(summary),
|
|
agentErrorMessage: statusSummaryActiveErrorPreview(
|
|
summary,
|
|
ctx.acknowledgedAgentErrors,
|
|
ctx.dismissedAgentErrors,
|
|
),
|
|
};
|
|
}
|
|
|
|
export function toSheetItem(
|
|
task: KanbanState["tasks"][number] & { _workflowId: string },
|
|
ctx: SheetItemCtx,
|
|
) {
|
|
const status = sheetStatus(task, ctx);
|
|
const facts = taskColorFacts(task, {
|
|
workspaceId: ctx.workspaceId,
|
|
repositoriesById: ctx.repositoriesById ?? EMPTY_REPOSITORIES_BY_ID,
|
|
stepColorById: ctx.stepColorById ?? EMPTY_STEP_COLORS,
|
|
});
|
|
const automaticColor = ctx.automaticColorSettings
|
|
? resolveAutomaticTaskColor(ctx.automaticColorSettings, facts)
|
|
: null;
|
|
return {
|
|
id: task.id,
|
|
title: task.title,
|
|
autopilot: task.autopilot,
|
|
priority: task.priority,
|
|
createdAt: task.createdAt,
|
|
lastActivityAt: sheetLastActivity(task),
|
|
parentTaskId: task.parentTaskId ?? undefined,
|
|
workspaceMode: task.workspaceMode,
|
|
state: task.state as TaskState | undefined,
|
|
...status,
|
|
interrupted: task.interrupted,
|
|
description: task.description,
|
|
workflowId: task._workflowId,
|
|
workflowName: ctx.workflowNameById.get(task._workflowId),
|
|
workflowStepId: task.workflowStepId,
|
|
workflowStepTitle: ctx.stepTitleById.get(task.workflowStepId),
|
|
workspaceId: facts.workspaceId,
|
|
origin: task.origin,
|
|
primaryExecutorProfileId: task.primaryExecutorProfileId ?? undefined,
|
|
workflowStepColor: facts.workflowStepColor,
|
|
isArchived: task.isArchived === true,
|
|
isPendingArchive: !task.isArchived && ctx.pendingArchiveTaskIds?.has(task.id) === true,
|
|
isFromOffice: task.isFromOffice,
|
|
isRemoteExecutor: task.isRemoteExecutor,
|
|
remoteExecutorId: task.primaryExecutorId ?? undefined,
|
|
remoteExecutorType: task.primaryExecutorType ?? undefined,
|
|
remoteExecutorName: task.primaryExecutorName ?? undefined,
|
|
repositoryLinks: task.repositories,
|
|
repositoryRuleIdentities: facts.repositories,
|
|
automaticColor: automaticColor?.color,
|
|
automaticColorSource: automaticColor?.source,
|
|
queuedCount: task.statusSummary?.queued_prompt_count,
|
|
launchQueue: sheetLaunchQueue(task),
|
|
wipQueue: ctx.wipQueueByTaskId?.get(task.id),
|
|
};
|
|
}
|