Skip to content

Commit 341a653

Browse files
gsxdsmclaude
andcommitted
refactor: extract shared isBacklogLikeStatus helper and improve comments
Address PR #825 review feedback: - Extract duplicated backlog-like status check into shared helper in constants.ts - Improve spec-parser regex comment to clarify subsection preservation - Add file path reference in row-actions.tsx comment for traceability Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4a128ef commit 341a653

4 files changed

Lines changed: 57 additions & 43 deletions

File tree

apps/server/src/services/spec-parser.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,8 @@ export function extractSummary(text: string): string | null {
214214
}
215215

216216
// Check for ## Summary section (use last match)
217-
// Use \n## [^#] to stop at same-level headers (## Foo) but NOT subsections (### Root Cause)
217+
// Stop at \n## [^#] (same-level headers like "## Changes") but preserve ### subsections
218+
// (like "### Root Cause", "### Fix Applied") that belong to the summary content.
218219
const sectionMatches = text.matchAll(/##\s*Summary\s*\n+([\s\S]*?)(?=\n## [^#]|\n\*\*|$)/gi);
219220
const sectionMatch = getLastMatch(sectionMatches);
220221
if (sectionMatch) {

apps/ui/src/components/views/board-view.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ import type {
8383
StashApplyConflictInfo,
8484
} from './board-view/worktree-panel/types';
8585
import { BoardErrorBoundary } from './board-view/board-error-boundary';
86-
import { COLUMNS, getColumnsWithPipeline } from './board-view/constants';
86+
import { COLUMNS, getColumnsWithPipeline, isBacklogLikeStatus } from './board-view/constants';
8787
import {
8888
useBoardFeatures,
8989
useBoardDragDrop,
@@ -1908,12 +1908,7 @@ export function BoardView({ initialFeatureId }: BoardViewProps) {
19081908
// Running features should always show logs, even if status is
19091909
// stale (still 'backlog'/'ready'/'interrupted' during race window)
19101910
const isRunning = runningAutoTasksAllWorktrees.includes(feature.id);
1911-
const isBacklogLike =
1912-
feature.status === 'backlog' ||
1913-
feature.status === 'merge_conflict' ||
1914-
feature.status === 'ready' ||
1915-
feature.status === 'interrupted';
1916-
if (isBacklogLike && !isRunning) {
1911+
if (isBacklogLikeStatus(feature.status) && !isRunning) {
19171912
setEditingFeature(feature);
19181913
} else {
19191914
handleViewOutput(feature);

apps/ui/src/components/views/board-view/components/list-view/row-actions.tsx

Lines changed: 33 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
DropdownMenuTrigger,
3131
} from '@/components/ui/dropdown-menu';
3232
import type { Feature } from '@/store/app-store';
33+
import { isBacklogLikeStatus } from '../../constants';
3334

3435
/**
3536
* Action handler types for row actions
@@ -431,44 +432,41 @@ export const RowActions = memo(function RowActions({
431432
</>
432433
)}
433434

434-
{/* Running task with stale status (backlog/ready/interrupted but tracked as running).
435+
{/* Running task with stale status - the feature is tracked as running but its
436+
persisted status hasn't caught up yet during WebSocket/cache sync delays.
435437
These features are placed in the in_progress column by useBoardColumnFeatures
436-
but their actual status hasn't updated yet, so no other menu block matches. */}
437-
{!isCurrentAutoTask &&
438-
isRunningTask &&
439-
(feature.status === 'backlog' ||
440-
feature.status === 'ready' ||
441-
feature.status === 'interrupted' ||
442-
feature.status === 'merge_conflict') && (
443-
<>
444-
{handlers.onViewOutput && (
445-
<MenuItem
446-
icon={FileText}
447-
label="View Logs"
448-
onClick={withClose(handlers.onViewOutput)}
449-
/>
450-
)}
451-
<MenuItem icon={Edit} label="Edit" onClick={withClose(handlers.onEdit)} />
452-
{handlers.onSpawnTask && (
438+
(hooks/use-board-column-features.ts) but no other menu block matches their
439+
stale status, so we provide running-appropriate actions here. */}
440+
{!isCurrentAutoTask && isRunningTask && isBacklogLikeStatus(feature.status) && (
441+
<>
442+
{handlers.onViewOutput && (
443+
<MenuItem
444+
icon={FileText}
445+
label="View Logs"
446+
onClick={withClose(handlers.onViewOutput)}
447+
/>
448+
)}
449+
<MenuItem icon={Edit} label="Edit" onClick={withClose(handlers.onEdit)} />
450+
{handlers.onSpawnTask && (
451+
<MenuItem
452+
icon={GitFork}
453+
label="Spawn Sub-Task"
454+
onClick={withClose(handlers.onSpawnTask)}
455+
/>
456+
)}
457+
{handlers.onForceStop && (
458+
<>
459+
<DropdownMenuSeparator />
453460
<MenuItem
454-
icon={GitFork}
455-
label="Spawn Sub-Task"
456-
onClick={withClose(handlers.onSpawnTask)}
461+
icon={StopCircle}
462+
label="Force Stop"
463+
onClick={withClose(handlers.onForceStop)}
464+
variant="destructive"
457465
/>
458-
)}
459-
{handlers.onForceStop && (
460-
<>
461-
<DropdownMenuSeparator />
462-
<MenuItem
463-
icon={StopCircle}
464-
label="Force Stop"
465-
onClick={withClose(handlers.onForceStop)}
466-
variant="destructive"
467-
/>
468-
</>
469-
)}
470-
</>
471-
)}
466+
</>
467+
)}
468+
</>
469+
)}
472470

473471
{/* Backlog actions */}
474472
{!isCurrentAutoTask &&

apps/ui/src/components/views/board-view/constants.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,26 @@ export function getPipelineInsertIndex(): number {
136136
return BASE_COLUMNS.length;
137137
}
138138

139+
/**
140+
* Statuses that display in the backlog column because they don't have dedicated columns:
141+
* - 'backlog': Default state for new features
142+
* - 'ready': Feature has an approved plan, waiting for execution
143+
* - 'interrupted': Feature execution was aborted (user stopped it, server restart)
144+
* - 'merge_conflict': Automatic merge failed, user must resolve conflicts
145+
*
146+
* Used to determine row click behavior and menu actions when a feature is running
147+
* but its status hasn't updated yet (race condition during WebSocket/cache sync).
148+
* See use-board-column-features.ts for the column assignment logic.
149+
*/
150+
export function isBacklogLikeStatus(status: string): boolean {
151+
return (
152+
status === 'backlog' ||
153+
status === 'ready' ||
154+
status === 'interrupted' ||
155+
status === 'merge_conflict'
156+
);
157+
}
158+
139159
/**
140160
* Check if a status is a pipeline status
141161
*/

0 commit comments

Comments
 (0)