fix: adjust pr commnets

This commit is contained in:
Shirone
2026-01-12 21:21:20 +01:00
parent 19c12b7813
commit cca4638b71
15 changed files with 91 additions and 271 deletions

View File

@@ -263,7 +263,7 @@ export function BoardHeader({
/>
{/* Plan Button with Settings - only show on desktop, mobile has it in the menu */}
{!isMobile && (
{isMounted && !isMobile && (
<div className={controlContainerClass} data-testid="plan-button-container">
<button
onClick={onOpenPlanDialog}

View File

@@ -1,4 +1,10 @@
export { ListHeader, LIST_COLUMNS, getColumnById, getColumnWidth, getColumnAlign } from './list-header';
export {
ListHeader,
LIST_COLUMNS,
getColumnById,
getColumnWidth,
getColumnAlign,
} from './list-header';
export type { ListHeaderProps } from './list-header';
export { ListRow, getFeatureSortValue, sortFeatures } from './list-row';

View File

@@ -1,3 +1,5 @@
// TODO: Remove @ts-nocheck after fixing BaseFeature's index signature issue
// The `[key: string]: unknown` in BaseFeature causes property access type errors
// @ts-nocheck
import { memo, useCallback, useMemo } from 'react';
import { cn } from '@/lib/utils';

View File

@@ -1,4 +1,3 @@
// @ts-nocheck
import { memo, useMemo, useCallback, useState } from 'react';
import { ChevronDown, ChevronRight, Plus } from 'lucide-react';
import { cn } from '@/lib/utils';
@@ -10,7 +9,7 @@ import { ListHeader } from './list-header';
import { ListRow, sortFeatures } from './list-row';
import { createRowActionHandlers, type RowActionHandlers } from './row-actions';
import { getStatusLabel, getStatusOrder } from './status-badge';
import { COLUMNS, getColumnsWithPipeline } from '../../constants';
import { getColumnsWithPipeline } from '../../constants';
import type { SortConfig, SortColumn } from '../../hooks/use-list-view-state';
/**
@@ -98,11 +97,7 @@ const StatusGroupHeader = memo(function StatusGroupHeader({
>
{/* Collapse indicator */}
<span className="text-muted-foreground">
{isExpanded ? (
<ChevronDown className="w-4 h-4" />
) : (
<ChevronRight className="w-4 h-4" />
)}
{isExpanded ? <ChevronDown className="w-4 h-4" /> : <ChevronRight className="w-4 h-4" />}
</span>
{/* Status color indicator */}
@@ -123,11 +118,7 @@ const StatusGroupHeader = memo(function StatusGroupHeader({
/**
* EmptyState displays a message when there are no features
*/
const EmptyState = memo(function EmptyState({
onAddFeature,
}: {
onAddFeature?: () => void;
}) {
const EmptyState = memo(function EmptyState({ onAddFeature }: { onAddFeature?: () => void }) {
return (
<div
className={cn(
@@ -210,11 +201,7 @@ export const ListView = memo(function ListView({
const features = columnFeaturesMap[column.id] || [];
if (features.length > 0) {
// Sort features within the group according to current sort config
const sortedFeatures = sortFeatures(
features,
sortConfig.column,
sortConfig.direction
);
const sortedFeatures = sortFeatures(features, sortConfig.column, sortConfig.direction);
groups.push({
id: column.id as FeatureStatusWithPipeline,
@@ -366,20 +353,12 @@ export const ListView = memo(function ListView({
}
}
}
}, [
onToggleFeatureSelection,
selectionState.allSelected,
selectedFeatureIds,
statusGroups,
]);
}, [onToggleFeatureSelection, selectionState.allSelected, selectedFeatureIds, statusGroups]);
// Show empty state if no features
if (totalFeatures === 0) {
return (
<div
className={cn('flex flex-col h-full bg-background', className)}
data-testid="list-view"
>
<div className={cn('flex flex-col h-full bg-background', className)} data-testid="list-view">
<EmptyState onAddFeature={onAddFeature} />
</div>
);
@@ -466,20 +445,13 @@ export const ListView = memo(function ListView({
/**
* Helper to get all features from the columnFeaturesMap as a flat array
*/
export function getFlatFeatures(
columnFeaturesMap: Record<string, Feature[]>
): Feature[] {
export function getFlatFeatures(columnFeaturesMap: Record<string, Feature[]>): Feature[] {
return Object.values(columnFeaturesMap).flat();
}
/**
* Helper to count total features across all groups
*/
export function getTotalFeatureCount(
columnFeaturesMap: Record<string, Feature[]>
): number {
return Object.values(columnFeaturesMap).reduce(
(sum, features) => sum + features.length,
0
);
export function getTotalFeatureCount(columnFeaturesMap: Record<string, Feature[]>): number {
return Object.values(columnFeaturesMap).reduce((sum, features) => sum + features.length, 0);
}

View File

@@ -1,4 +1,3 @@
// @ts-nocheck
import { memo, useCallback, useState } from 'react';
import {
MoreHorizontal,
@@ -253,7 +252,13 @@ export const RowActions = memo(function RowActions({
// Use controlled or uncontrolled state
const open = isOpen ?? internalOpen;
const setOpen = onOpenChange ?? setInternalOpen;
const setOpen = (value: boolean) => {
if (onOpenChange) {
onOpenChange(value);
} else {
setInternalOpen(value);
}
};
const handleOpenChange = useCallback(
(newOpen: boolean) => {

View File

@@ -160,10 +160,7 @@ export const StatusBadge = memo(function StatusBadge({
size = 'default',
className,
}: StatusBadgeProps) {
const display = useMemo(
() => getStatusDisplay(status, pipelineConfig),
[status, pipelineConfig]
);
const display = useMemo(() => getStatusDisplay(status, pipelineConfig), [status, pipelineConfig]);
const sizeClasses = {
sm: 'px-1.5 py-0.5 text-[10px]',

View File

@@ -98,17 +98,22 @@ export function CommitWorktreeDialog({
}
setIsGenerating(true);
let cancelled = false;
const generateMessage = async () => {
try {
const api = getElectronAPI();
if (!api?.worktree?.generateCommitMessage) {
setIsGenerating(false);
if (!cancelled) {
setIsGenerating(false);
}
return;
}
const result = await api.worktree.generateCommitMessage(worktree.path);
if (cancelled) return;
if (result.success && result.message) {
setMessage(result.message);
} else {
@@ -117,15 +122,22 @@ export function CommitWorktreeDialog({
setMessage('');
}
} catch (err) {
if (cancelled) return;
// Don't show error toast for generation failures
console.warn('Error generating commit message:', err);
setMessage('');
} finally {
setIsGenerating(false);
if (!cancelled) {
setIsGenerating(false);
}
}
};
generateMessage();
return () => {
cancelled = true;
};
}
}, [open, worktree, enableAiCommitMessages]);

View File

@@ -52,7 +52,14 @@ function validateViewMode(value: unknown): ViewMode {
* Validates and returns a valid SortColumn, defaulting to 'createdAt' if invalid
*/
function validateSortColumn(value: unknown): SortColumn {
const validColumns: SortColumn[] = ['title', 'status', 'category', 'priority', 'createdAt', 'updatedAt'];
const validColumns: SortColumn[] = [
'title',
'status',
'category',
'priority',
'createdAt',
'updatedAt',
];
if (typeof value === 'string' && validColumns.includes(value as SortColumn)) {
return value as SortColumn;
}
@@ -139,7 +146,9 @@ export interface UseListViewStateReturn {
export function useListViewState(): UseListViewStateReturn {
// Initialize state from localStorage
const [viewMode, setViewModeState] = useState<ViewMode>(() => loadPersistedState().viewMode);
const [sortConfig, setSortConfigState] = useState<SortConfig>(() => loadPersistedState().sortConfig);
const [sortConfig, setSortConfigState] = useState<SortConfig>(
() => loadPersistedState().sortConfig
);
// Derived state
const isListView = viewMode === 'list';
@@ -199,6 +208,16 @@ export function useListViewState(): UseListViewStateReturn {
setSortConfig,
resetSort,
}),
[viewMode, setViewMode, toggleViewMode, isListView, isKanbanView, sortConfig, setSortColumn, setSortConfig, resetSort]
[
viewMode,
setViewMode,
toggleViewMode,
isListView,
isKanbanView,
sortConfig,
setSortColumn,
setSortConfig,
resetSort,
]
);
}

View File

@@ -9,8 +9,6 @@ import { useResponsiveKanban } from '@/hooks/use-responsive-kanban';
import { getColumnsWithPipeline, type ColumnId } from './constants';
import type { PipelineConfig } from '@automaker/types';
import { cn } from '@/lib/utils';
import type { ViewMode } from './hooks/use-list-view-state';
interface KanbanBoardProps {
sensors: any;
collisionDetectionStrategy: (args: any) => any;
@@ -59,8 +57,6 @@ interface KanbanBoardProps {
isDragging?: boolean;
/** Whether the board is in read-only mode */
isReadOnly?: boolean;
// View mode for transition animation
viewMode?: ViewMode;
/** Additional className for custom styling (e.g., transition classes) */
className?: string;
}
@@ -101,7 +97,6 @@ export function KanbanBoard({
onAiSuggest,
isDragging = false,
isReadOnly = false,
viewMode,
className,
}: KanbanBoardProps) {
// Generate columns including pipeline steps

View File

@@ -1,4 +1,4 @@
import { useEffect, useCallback } from 'react';
import { useEffect, useCallback, useState } from 'react';
import { RefreshCw, AlertTriangle } from 'lucide-react';
import { cn } from '@/lib/utils';
import { getElectronAPI } from '@/lib/electron';
@@ -104,6 +104,8 @@ function UsageItem({
export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageBarProps) {
const { claudeUsage, claudeUsageLastUpdated, setClaudeUsage } = useAppStore();
const { codexUsage, codexUsageLastUpdated, setCodexUsage } = useAppStore();
const [isClaudeLoading, setIsClaudeLoading] = useState(false);
const [isCodexLoading, setIsCodexLoading] = useState(false);
// Check if data is stale (older than 2 minutes)
const isClaudeStale =
@@ -111,6 +113,7 @@ export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageB
const isCodexStale = !codexUsageLastUpdated || Date.now() - codexUsageLastUpdated > 2 * 60 * 1000;
const fetchClaudeUsage = useCallback(async () => {
setIsClaudeLoading(true);
try {
const api = getElectronAPI();
if (!api.claude) return;
@@ -120,10 +123,13 @@ export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageB
}
} catch {
// Silently fail - usage display is optional
} finally {
setIsClaudeLoading(false);
}
}, [setClaudeUsage]);
const fetchCodexUsage = useCallback(async () => {
setIsCodexLoading(true);
try {
const api = getElectronAPI();
if (!api.codex) return;
@@ -133,6 +139,8 @@ export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageB
}
} catch {
// Silently fail - usage display is optional
} finally {
setIsCodexLoading(false);
}
}, [setCodexUsage]);
@@ -166,7 +174,7 @@ export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageB
<UsageItem
icon={AnthropicIcon}
label="Claude"
isLoading={false}
isLoading={isClaudeLoading}
onRefresh={fetchClaudeUsage}
>
{claudeUsage ? (
@@ -189,7 +197,12 @@ export function MobileUsageBar({ showClaudeUsage, showCodexUsage }: MobileUsageB
)}
{showCodexUsage && (
<UsageItem icon={OpenAIIcon} label="Codex" isLoading={false} onRefresh={fetchCodexUsage}>
<UsageItem
icon={OpenAIIcon}
label="Codex"
isLoading={isCodexLoading}
onRefresh={fetchCodexUsage}
>
{codexUsage?.rateLimits ? (
<>
{codexUsage.rateLimits.primary && (

View File

@@ -235,6 +235,8 @@ export function WorktreePanel({
onStartDevServer={handleStartDevServer}
onStopDevServer={handleStopDevServer}
onOpenDevServerUrl={handleOpenDevServerUrl}
onRunInitScript={handleRunInitScript}
hasInitScript={hasInitScript}
/>
)}