feat(integration): WP-3 workflow filter integration
Apply workflow state filter to displayed issues using enrichment data. Unenriched issues treated as 'new' for filtering. Pass enrichments map to IssueList for data flow. Use workflowFilteredIssues instead of raw filteredIssues. Co-Authored-By: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
b649b9b91f
commit
cbbe06347c
@@ -96,6 +96,15 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
|
||||
const stateCounts = useEnrichmentStore((s) => s.getStateCounts());
|
||||
const [workflowFilter, setWorkflowFilter] = useState<WorkflowState[]>([]);
|
||||
|
||||
// Apply workflow filter to issues
|
||||
const workflowFilteredIssues = useMemo(() => {
|
||||
if (workflowFilter.length === 0) return filteredIssues;
|
||||
return filteredIssues.filter((issue) => {
|
||||
const state = enrichments[String(issue.number)]?.triageState ?? 'new';
|
||||
return workflowFilter.includes(state);
|
||||
});
|
||||
}, [filteredIssues, workflowFilter, enrichments]);
|
||||
|
||||
const [showInvestigateDialog, setShowInvestigateDialog] = useState(false);
|
||||
const [selectedIssueForInvestigation, setSelectedIssueForInvestigation] =
|
||||
useState<GitHubIssue | null>(null);
|
||||
@@ -203,7 +212,7 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
|
||||
{/* Issue List */}
|
||||
<div className="w-1/2 border-r border-border flex flex-col">
|
||||
<IssueList
|
||||
issues={filteredIssues}
|
||||
issues={workflowFilteredIssues}
|
||||
selectedIssueNumber={selectedIssueNumber}
|
||||
isLoading={isLoading}
|
||||
isLoadingMore={isLoadingMore}
|
||||
@@ -212,6 +221,7 @@ export function GitHubIssues({ onOpenSettings, onNavigateToTask }: GitHubIssuesP
|
||||
onSelectIssue={selectIssue}
|
||||
onInvestigate={handleInvestigate}
|
||||
onLoadMore={!isSearchActive ? handleLoadMore : undefined}
|
||||
enrichments={enrichments}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import type { IssueEnrichment, WorkflowState } from '../../../../shared/types/enrichment';
|
||||
|
||||
/**
|
||||
* Unit tests for the workflow filter logic extracted from GitHubIssues container.
|
||||
* Tests the pure filtering function without React rendering.
|
||||
*/
|
||||
|
||||
interface MinimalIssue {
|
||||
number: number;
|
||||
state: 'open' | 'closed';
|
||||
title: string;
|
||||
}
|
||||
|
||||
function applyWorkflowFilter(
|
||||
issues: MinimalIssue[],
|
||||
enrichments: Record<string, Partial<IssueEnrichment>>,
|
||||
workflowFilter: WorkflowState[],
|
||||
): MinimalIssue[] {
|
||||
if (workflowFilter.length === 0) return issues;
|
||||
return issues.filter((issue) => {
|
||||
const state = (enrichments[String(issue.number)]?.triageState ?? 'new') as WorkflowState;
|
||||
return workflowFilter.includes(state);
|
||||
});
|
||||
}
|
||||
|
||||
const issues: MinimalIssue[] = [
|
||||
{ number: 1, state: 'open', title: 'Issue 1' },
|
||||
{ number: 2, state: 'open', title: 'Issue 2' },
|
||||
{ number: 3, state: 'closed', title: 'Issue 3' },
|
||||
{ number: 4, state: 'open', title: 'Issue 4' },
|
||||
{ number: 5, state: 'open', title: 'Issue 5' },
|
||||
];
|
||||
|
||||
const enrichments: Record<string, Partial<IssueEnrichment>> = {
|
||||
'1': { triageState: 'new' as WorkflowState },
|
||||
'2': { triageState: 'triage' as WorkflowState },
|
||||
'3': { triageState: 'done' as WorkflowState },
|
||||
'4': { triageState: 'ready' as WorkflowState },
|
||||
// Issue 5 has no enrichment — defaults to 'new'
|
||||
};
|
||||
|
||||
describe('Workflow filter integration', () => {
|
||||
it('empty filter shows all issues', () => {
|
||||
const result = applyWorkflowFilter(issues, enrichments, []);
|
||||
expect(result.length).toBe(5);
|
||||
});
|
||||
|
||||
it('filter to new shows unenriched issues and new state', () => {
|
||||
const result = applyWorkflowFilter(issues, enrichments, ['new']);
|
||||
expect(result.map((i) => i.number)).toEqual([1, 5]);
|
||||
});
|
||||
|
||||
it('filter to triage and ready shows matching issues', () => {
|
||||
const result = applyWorkflowFilter(issues, enrichments, ['triage', 'ready']);
|
||||
expect(result.map((i) => i.number)).toEqual([2, 4]);
|
||||
});
|
||||
|
||||
it('filter to done includes closed issues with done state', () => {
|
||||
const result = applyWorkflowFilter(issues, enrichments, ['done']);
|
||||
expect(result.map((i) => i.number)).toEqual([3]);
|
||||
});
|
||||
|
||||
it('combines with pre-filtered issues (simulating text search)', () => {
|
||||
// Simulate text search already filtering to issues 1, 2, 3
|
||||
const preFiltered = issues.filter((i) => i.number <= 3);
|
||||
const result = applyWorkflowFilter(preFiltered, enrichments, ['new']);
|
||||
expect(result.map((i) => i.number)).toEqual([1]);
|
||||
});
|
||||
|
||||
it('returns empty when no issues match filter', () => {
|
||||
const result = applyWorkflowFilter(issues, enrichments, ['in_progress']);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user