taskStatusUtils.tsx
components/tasks/taskStatusUtils.tsx
107
Lines
13548
Bytes
5
Exports
7
Imports
10
Keywords
What this is
This page documents one file from the repository and includes its full source so you can read it without leaving the docs site.
Beginner explanation
This file is one piece of the larger system. Its name, directory, imports, and exports show where it fits. Start by reading the exports and related files first.
How it is used
Start from the exports list and related files. Those are the easiest clues for where this file fits into the system.
Expert explanation
Architecturally, this file intersects with tasks-background-jobs, ui-flow. It contains 107 lines, 7 detected imports, and 5 detected exports.
Important relationships
- components/tasks/AsyncAgentDetailDialog.tsx
- components/tasks/BackgroundTask.tsx
- components/tasks/BackgroundTaskStatus.tsx
- components/tasks/BackgroundTasksDialog.tsx
- components/tasks/DreamDetailDialog.tsx
- components/tasks/InProcessTeammateDetailDialog.tsx
- components/tasks/RemoteSessionDetailDialog.tsx
- components/tasks/RemoteSessionProgress.tsx
Detected exports
isTerminalStatusgetTaskStatusIcongetTaskStatusColordescribeTeammateActivityshouldHideTasksFooter
Keywords
statusfigurestaskisidleshutdownrequestedtasksawaitingapprovalhaserrorwarningtypes
Detected imports
figuressrc/Task.jssrc/tasks/InProcessTeammateTask/types.jssrc/tasks/LocalAgentTask/LocalAgentTask.jssrc/tasks/types.jssrc/types/utils.jssrc/utils/collapseReadSearch.js
Source notes
This page embeds the full file contents. Small or leaf files are still indexed honestly instead of being over-explained.
Full source
/**
* Shared utilities for displaying task status across different task types.
*/
import figures from 'figures';
import type { TaskStatus } from 'src/Task.js';
import type { InProcessTeammateTaskState } from 'src/tasks/InProcessTeammateTask/types.js';
import { isPanelAgentTask } from 'src/tasks/LocalAgentTask/LocalAgentTask.js';
import { isBackgroundTask, type TaskState } from 'src/tasks/types.js';
import type { DeepImmutable } from 'src/types/utils.js';
import { summarizeRecentActivities } from 'src/utils/collapseReadSearch.js';
/**
* Returns true if the given task status represents a terminal (finished) state.
*/
export function isTerminalStatus(status: TaskStatus): boolean {
return status === 'completed' || status === 'failed' || status === 'killed';
}
/**
* Returns the appropriate icon for a task based on status and state flags.
*/
export function getTaskStatusIcon(status: TaskStatus, options?: {
isIdle?: boolean;
awaitingApproval?: boolean;
hasError?: boolean;
shutdownRequested?: boolean;
}): string {
const {
isIdle,
awaitingApproval,
hasError,
shutdownRequested
} = options ?? {};
if (hasError) return figures.cross;
if (awaitingApproval) return figures.questionMarkPrefix;
if (shutdownRequested) return figures.warning;
if (status === 'running') {
if (isIdle) return figures.ellipsis;
return figures.play;
}
if (status === 'completed') return figures.tick;
if (status === 'failed' || status === 'killed') return figures.cross;
return figures.bullet;
}
/**
* Returns the appropriate semantic color for a task based on status and state flags.
*/
export function getTaskStatusColor(status: TaskStatus, options?: {
isIdle?: boolean;
awaitingApproval?: boolean;
hasError?: boolean;
shutdownRequested?: boolean;
}): 'success' | 'error' | 'warning' | 'background' {
const {
isIdle,
awaitingApproval,
hasError,
shutdownRequested
} = options ?? {};
if (hasError) return 'error';
if (awaitingApproval) return 'warning';
if (shutdownRequested) return 'warning';
if (isIdle) return 'background';
if (status === 'completed') return 'success';
if (status === 'failed') return 'error';
if (status === 'killed') return 'warning';
return 'background';
}
/**
* Derives a human-readable activity string for an in-process teammate,
* accounting for shutdown/approval/idle states and falling back through
* recent-activity summary → last activity description → 'working'.
*/
export function describeTeammateActivity(t: DeepImmutable<InProcessTeammateTaskState>): string {
if (t.shutdownRequested) return 'stopping';
if (t.awaitingPlanApproval) return 'awaiting approval';
if (t.isIdle) return 'idle';
return (t.progress?.recentActivities && summarizeRecentActivities(t.progress.recentActivities)) ?? t.progress?.lastActivity?.activityDescription ?? 'working';
}
/**
* Returns true when BackgroundTaskStatus would render nothing because the
* spinner tree is active and every visible background task is an in-process
* teammate (teammates are shown in the spinner tree instead).
*
* Uses the same task filtering as BackgroundTaskStatus: `isBackgroundTask()`
* plus exclusion of panel-managed agent tasks for ants (those are shown
* by CoordinatorTaskPanel).
*/
export function shouldHideTasksFooter(tasks: {
[taskId: string]: TaskState;
}, showSpinnerTree: boolean): boolean {
if (!showSpinnerTree) return false;
let hasVisibleTask = false;
for (const t of Object.values(tasks) as TaskState[]) {
if (!isBackgroundTask(t) || "external" === 'ant' && isPanelAgentTask(t)) {
continue;
}
hasVisibleTask = true;
if (t.type !== 'in_process_teammate') return false;
}
return hasVisibleTask;
}
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJmaWd1cmVzIiwiVGFza1N0YXR1cyIsIkluUHJvY2Vzc1RlYW1tYXRlVGFza1N0YXRlIiwiaXNQYW5lbEFnZW50VGFzayIsImlzQmFja2dyb3VuZFRhc2siLCJUYXNrU3RhdGUiLCJEZWVwSW1tdXRhYmxlIiwic3VtbWFyaXplUmVjZW50QWN0aXZpdGllcyIsImlzVGVybWluYWxTdGF0dXMiLCJzdGF0dXMiLCJnZXRUYXNrU3RhdHVzSWNvbiIsIm9wdGlvbnMiLCJpc0lkbGUiLCJhd2FpdGluZ0FwcHJvdmFsIiwiaGFzRXJyb3IiLCJzaHV0ZG93blJlcXVlc3RlZCIsImNyb3NzIiwicXVlc3Rpb25NYXJrUHJlZml4Iiwid2FybmluZyIsImVsbGlwc2lzIiwicGxheSIsInRpY2siLCJidWxsZXQiLCJnZXRUYXNrU3RhdHVzQ29sb3IiLCJkZXNjcmliZVRlYW1tYXRlQWN0aXZpdHkiLCJ0IiwiYXdhaXRpbmdQbGFuQXBwcm92YWwiLCJwcm9ncmVzcyIsInJlY2VudEFjdGl2aXRpZXMiLCJsYXN0QWN0aXZpdHkiLCJhY3Rpdml0eURlc2NyaXB0aW9uIiwic2hvdWxkSGlkZVRhc2tzRm9vdGVyIiwidGFza3MiLCJ0YXNrSWQiLCJzaG93U3Bpbm5lclRyZWUiLCJoYXNWaXNpYmxlVGFzayIsIk9iamVjdCIsInZhbHVlcyIsInR5cGUiXSwic291cmNlcyI6WyJ0YXNrU3RhdHVzVXRpbHMudHN4Il0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogU2hhcmVkIHV0aWxpdGllcyBmb3IgZGlzcGxheWluZyB0YXNrIHN0YXR1cyBhY3Jvc3MgZGlmZmVyZW50IHRhc2sgdHlwZXMuXG4gKi9cblxuaW1wb3J0IGZpZ3VyZXMgZnJvbSAnZmlndXJlcydcbmltcG9ydCB0eXBlIHsgVGFza1N0YXR1cyB9IGZyb20gJ3NyYy9UYXNrLmpzJ1xuaW1wb3J0IHR5cGUgeyBJblByb2Nlc3NUZWFtbWF0ZVRhc2tTdGF0ZSB9IGZyb20gJ3NyYy90YXNrcy9JblByb2Nlc3NUZWFtbWF0ZVRhc2svdHlwZXMuanMnXG5pbXBvcnQgeyBpc1BhbmVsQWdlbnRUYXNrIH0gZnJvbSAnc3JjL3Rhc2tzL0xvY2FsQWdlbnRUYXNrL0xvY2FsQWdlbnRUYXNrLmpzJ1xuaW1wb3J0IHsgaXNCYWNrZ3JvdW5kVGFzaywgdHlwZSBUYXNrU3RhdGUgfSBmcm9tICdzcmMvdGFza3MvdHlwZXMuanMnXG5pbXBvcnQgdHlwZSB7IERlZXBJbW11dGFibGUgfSBmcm9tICdzcmMvdHlwZXMvdXRpbHMuanMnXG5pbXBvcnQgeyBzdW1tYXJpemVSZWNlbnRBY3Rpdml0aWVzIH0gZnJvbSAnc3JjL3V0aWxzL2NvbGxhcHNlUmVhZFNlYXJjaC5qcydcblxuLyoqXG4gKiBSZXR1cm5zIHRydWUgaWYgdGhlIGdpdmVuIHRhc2sgc3RhdHVzIHJlcHJlc2VudHMgYSB0ZXJtaW5hbCAoZmluaXNoZWQpIHN0YXRlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNUZXJtaW5hbFN0YXR1cyhzdGF0dXM6IFRhc2tTdGF0dXMpOiBib29sZWFuIHtcbiAgcmV0dXJuIHN0YXR1cyA9PT0gJ2NvbXBsZXRlZCcgfHwgc3RhdHVzID09PSAnZmFpbGVkJyB8fCBzdGF0dXMgPT09ICdraWxsZWQnXG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgYXBwcm9wcmlhdGUgaWNvbiBmb3IgYSB0YXNrIGJhc2VkIG9uIHN0YXR1cyBhbmQgc3RhdGUgZmxhZ3MuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRUYXNrU3RhdHVzSWNvbihcbiAgc3RhdHVzOiBUYXNrU3RhdHVzLFxuICBvcHRpb25zPzoge1xuICAgIGlzSWRsZT86IGJvb2xlYW5cbiAgICBhd2FpdGluZ0FwcHJvdmFsPzogYm9vbGVhblxuICAgIGhhc0Vycm9yPzogYm9vbGVhblxuICAgIHNodXRkb3duUmVxdWVzdGVkPzogYm9vbGVhblxuICB9LFxuKTogc3RyaW5nIHtcbiAgY29uc3QgeyBpc0lkbGUsIGF3YWl0aW5nQXBwcm92YWwsIGhhc0Vycm9yLCBzaHV0ZG93blJlcXVlc3RlZCB9ID1cbiAgICBvcHRpb25zID8/IHt9XG5cbiAgaWYgKGhhc0Vycm9yKSByZXR1cm4gZmlndXJlcy5jcm9zc1xuICBpZiAoYXdhaXRpbmdBcHByb3ZhbCkgcmV0dXJuIGZpZ3VyZXMucXVlc3Rpb25NYXJrUHJlZml4XG4gIGlmIChzaHV0ZG93blJlcXVlc3RlZCkgcmV0dXJuIGZpZ3VyZXMud2FybmluZ1xuXG4gIGlmIChzdGF0dXMgPT09ICdydW5uaW5nJykge1xuICAgIGlmIChpc0lkbGUpIHJldHVybiBmaWd1cmVzLmVsbGlwc2lzXG4gICAgcmV0dXJuIGZpZ3VyZXMucGxheVxuICB9XG4gIGlmIChzdGF0dXMgPT09ICdjb21wbGV0ZWQnKSByZXR1cm4gZmlndXJlcy50aWNrXG4gIGlmIChzdGF0dXMgPT09ICdmYWlsZWQnIHx8IHN0YXR1cyA9PT0gJ2tpbGxlZCcpIHJldHVybiBmaWd1cmVzLmNyb3NzXG4gIHJldHVybiBmaWd1cmVzLmJ1bGxldFxufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIGFwcHJvcHJpYXRlIHNlbWFudGljIGNvbG9yIGZvciBhIHRhc2sgYmFzZWQgb24gc3RhdHVzIGFuZCBzdGF0ZSBmbGFncy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFRhc2tTdGF0dXNDb2xvcihcbiAgc3RhdHVzOiBUYXNrU3RhdHVzLFxuICBvcHRpb25zPzoge1xuICAgIGlzSWRsZT86IGJvb2xlYW5cbiAgICBhd2FpdGluZ0FwcHJvdmFsPzogYm9vbGVhblxuICAgIGhhc0Vycm9yPzogYm9vbGVhblxuICAgIHNodXRkb3duUmVxdWVzdGVkPzogYm9vbGVhblxuICB9LFxuKTogJ3N1Y2Nlc3MnIHwgJ2Vycm9yJyB8ICd3YXJuaW5nJyB8ICdiYWNrZ3JvdW5kJyB7XG4gIGNvbnN0IHsgaXNJZGxlLCBhd2FpdGluZ0FwcHJvdmFsLCBoYXNFcnJvciwgc2h1dGRvd25SZXF1ZXN0ZWQgfSA9XG4gICAgb3B0aW9ucyA/PyB7fVxuXG4gIGlmIChoYXNFcnJvcikgcmV0dXJuICdlcnJvcidcbiAgaWYgKGF3YWl0aW5nQXBwcm92YWwpIHJldHVybiAnd2FybmluZydcbiAgaWYgKHNodXRkb3duUmVxdWVzdGVkKSByZXR1cm4gJ3dhcm5pbmcnXG4gIGlmIChpc0lkbGUpIHJldHVybiAnYmFja2dyb3VuZCdcblxuICBpZiAoc3RhdHVzID09PSAnY29tcGxldGVkJykgcmV0dXJuICdzdWNjZXNzJ1xuICBpZiAoc3RhdHVzID09PSAnZmFpbGVkJykgcmV0dXJuICdlcnJvcidcbiAgaWYgKHN0YXR1cyA9PT0gJ2tpbGxlZCcpIHJldHVybiAnd2FybmluZydcbiAgcmV0dXJuICdiYWNrZ3JvdW5kJ1xufVxuXG4vKipcbiAqIERlcml2ZXMgYSBodW1hbi1yZWFkYWJsZSBhY3Rpdml0eSBzdHJpbmcgZm9yIGFuIGluLXByb2Nlc3MgdGVhbW1hdGUsXG4gKiBhY2NvdW50aW5nIGZvciBzaHV0ZG93bi9hcHByb3ZhbC9pZGxlIHN0YXRlcyBhbmQgZmFsbGluZyBiYWNrIHRocm91Z2hcbiAqIHJlY2VudC1hY3Rpdml0eSBzdW1tYXJ5IOKGkiBsYXN0IGFjdGl2aXR5IGRlc2NyaXB0aW9uIOKGkiAnd29ya2luZycuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBkZXNjcmliZVRlYW1tYXRlQWN0aXZpdHkoXG4gIHQ6IERlZXBJbW11dGFibGU8SW5Qcm9jZXNzVGVhbW1hdGVUYXNrU3RhdGU+LFxuKTogc3RyaW5nIHtcbiAgaWYgKHQuc2h1dGRvd25SZXF1ZXN0ZWQpIHJldHVybiAnc3RvcHBpbmcnXG4gIGlmICh0LmF3YWl0aW5nUGxhbkFwcHJvdmFsKSByZXR1cm4gJ2F3YWl0aW5nIGFwcHJvdmFsJ1xuICBpZiAodC5pc0lkbGUpIHJldHVybiAnaWRsZSdcbiAgcmV0dXJuIChcbiAgICAodC5wcm9ncmVzcz8ucmVjZW50QWN0aXZpdGllcyAmJlxuICAgICAgc3VtbWFyaXplUmVjZW50QWN0aXZpdGllcyh0LnByb2dyZXNzLnJlY2VudEFjdGl2aXRpZXMpKSA/P1xuICAgIHQucHJvZ3Jlc3M/Lmxhc3RBY3Rpdml0eT8uYWN0aXZpdHlEZXNjcmlwdGlvbiA/P1xuICAgICd3b3JraW5nJ1xuICApXG59XG5cbi8qKlxuICogUmV0dXJucyB0cnVlIHdoZW4gQmFja2dyb3VuZFRhc2tTdGF0dXMgd291bGQgcmVuZGVyIG5vdGhpbmcgYmVjYXVzZSB0aGVcbiAqIHNwaW5uZXIgdHJlZSBpcyBhY3RpdmUgYW5kIGV2ZXJ5IHZpc2libGUgYmFja2dyb3VuZCB0YXNrIGlzIGFuIGluLXByb2Nlc3NcbiAqIHRlYW1tYXRlICh0ZWFtbWF0ZXMgYXJlIHNob3duIGluIHRoZSBzcGlubmVyIHRyZWUgaW5zdGVhZCkuXG4gKlxuICogVXNlcyB0aGUgc2FtZSB0YXNrIGZpbHRlcmluZyBhcyBCYWNrZ3JvdW5kVGFza1N0YXR1czogYGlzQmFja2dyb3VuZFRhc2soKWBcbiAqIHBsdXMgZXhjbHVzaW9uIG9mIHBhbmVsLW1hbmFnZWQgYWdlbnQgdGFza3MgZm9yIGFudHMgKHRob3NlIGFyZSBzaG93blxuICogYnkgQ29vcmRpbmF0b3JUYXNrUGFuZWwpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2hvdWxkSGlkZVRhc2tzRm9vdGVyKFxuICB0YXNrczogeyBbdGFza0lkOiBzdHJpbmddOiBUYXNrU3RhdGUgfSxcbiAgc2hvd1NwaW5uZXJUcmVlOiBib29sZWFuLFxuKTogYm9vbGVhbiB7XG4gIGlmICghc2hvd1NwaW5uZXJUcmVlKSByZXR1cm4gZmFsc2VcbiAgbGV0IGhhc1Zpc2libGVUYXNrID0gZmFsc2VcbiAgZm9yIChjb25zdCB0IG9mIE9iamVjdC52YWx1ZXModGFza3MpIGFzIFRhc2tTdGF0ZVtdKSB7XG4gICAgaWYgKFxuICAgICAgIWlzQmFja2dyb3VuZFRhc2sodCkgfHxcbiAgICAgIChcImV4dGVybmFsXCIgPT09ICdhbnQnICYmIGlzUGFuZWxBZ2VudFRhc2sodCkpXG4gICAgKSB7XG4gICAgICBjb250aW51ZVxuICAgIH1cbiAgICBoYXNWaXNpYmxlVGFzayA9IHRydWVcbiAgICBpZiAodC50eXBlICE9PSAnaW5fcHJvY2Vzc190ZWFtbWF0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