fix: adress pr comments

This commit is contained in:
Kacper
2026-01-16 21:05:58 +01:00
parent 6237f1a0fe
commit c0d64bc994
5 changed files with 48 additions and 33 deletions

View File

@@ -56,19 +56,23 @@ export function GitHubIssuesView() {
// Combine all issues for filtering // Combine all issues for filtering
const allIssues = useMemo(() => [...openIssues, ...closedIssues], [openIssues, closedIssues]); const allIssues = useMemo(() => [...openIssues, ...closedIssues], [openIssues, closedIssues]);
// Apply filter to issues // Apply filter to issues - now returns matched issues directly for better performance
const filterResult = useIssuesFilter(allIssues, filterState, cachedValidations); const filterResult = useIssuesFilter(allIssues, filterState, cachedValidations);
// Filter issues based on matched results // Separate filtered issues by state - this is O(n) but now only done once
const filteredOpenIssues = useMemo( // since filterResult.matchedIssues already contains the filtered issues
() => openIssues.filter((issue) => filterResult.matchedIssueNumbers.has(issue.number)), const { filteredOpenIssues, filteredClosedIssues } = useMemo(() => {
[openIssues, filterResult.matchedIssueNumbers] const open: typeof openIssues = [];
); const closed: typeof closedIssues = [];
for (const issue of filterResult.matchedIssues) {
const filteredClosedIssues = useMemo( if (issue.state.toLowerCase() === 'open') {
() => closedIssues.filter((issue) => filterResult.matchedIssueNumbers.has(issue.number)), open.push(issue);
[closedIssues, filterResult.matchedIssueNumbers] } else {
); closed.push(issue);
}
}
return { filteredOpenIssues: open, filteredClosedIssues: closed };
}, [filterResult.matchedIssues]);
// Filter state change handlers // Filter state change handlers
const handleStateFilterChange = useCallback((stateFilter: IssuesStateFilter) => { const handleStateFilterChange = useCallback((stateFilter: IssuesStateFilter) => {

View File

@@ -20,6 +20,11 @@ import { cn } from '@/lib/utils';
import type { IssuesStateFilter } from '../types'; import type { IssuesStateFilter } from '../types';
import { ISSUES_STATE_FILTER_OPTIONS } from '../types'; import { ISSUES_STATE_FILTER_OPTIONS } from '../types';
/** Maximum number of labels to display before showing "+N more" in normal layout */
const VISIBLE_LABELS_LIMIT = 3;
/** Maximum number of labels to display before showing "+N more" in compact layout */
const VISIBLE_LABELS_LIMIT_COMPACT = 2;
interface IssuesFilterControlsProps { interface IssuesFilterControlsProps {
/** Current state filter value */ /** Current state filter value */
stateFilter: IssuesStateFilter; stateFilter: IssuesStateFilter;
@@ -156,21 +161,27 @@ export function IssuesFilterControls({
{/* Selected Labels Display - shown on separate row */} {/* Selected Labels Display - shown on separate row */}
{hasSelectedLabels && ( {hasSelectedLabels && (
<div className="flex items-center gap-1 flex-wrap"> <div className="flex items-center gap-1 flex-wrap">
{selectedLabels.slice(0, compact ? 2 : 3).map((label) => ( {selectedLabels
<Badge .slice(0, compact ? VISIBLE_LABELS_LIMIT_COMPACT : VISIBLE_LABELS_LIMIT)
key={label} .map((label) => (
variant="outline" <Badge
size="sm" key={label}
className="gap-1 cursor-pointer hover:bg-destructive/10 hover:border-destructive/50" variant="outline"
onClick={() => handleLabelToggle(label)} size="sm"
> className="gap-1 cursor-pointer hover:bg-destructive/10 hover:border-destructive/50"
{label} onClick={() => handleLabelToggle(label)}
<X className="h-2.5 w-2.5" /> >
</Badge> {label}
))} <X className="h-2.5 w-2.5" />
{selectedLabels.length > (compact ? 2 : 3) && ( </Badge>
))}
{selectedLabels.length >
(compact ? VISIBLE_LABELS_LIMIT_COMPACT : VISIBLE_LABELS_LIMIT) && (
<Badge variant="muted" size="sm"> <Badge variant="muted" size="sm">
+{selectedLabels.length - (compact ? 2 : 3)} more +
{selectedLabels.length -
(compact ? VISIBLE_LABELS_LIMIT_COMPACT : VISIBLE_LABELS_LIMIT)}{' '}
more
</Badge> </Badge>
)} )}
</div> </div>

View File

@@ -200,8 +200,9 @@ export function useIssuesFilter(
// Normalize search query for case-insensitive matching // Normalize search query for case-insensitive matching
const normalizedQuery = searchQuery.toLowerCase().trim(); const normalizedQuery = searchQuery.toLowerCase().trim();
// Filter issues based on all criteria // Filter issues based on all criteria - return matched issues directly
const matchedIssueNumbers = new Set<number>(); // This eliminates the redundant O(n) filtering operation in the consuming component
const matchedIssues: GitHubIssue[] = [];
for (const issue of issues) { for (const issue of issues) {
// All conditions must be true for a match // All conditions must be true for a match
@@ -214,17 +215,17 @@ export function useIssuesFilter(
matchesValidationStatus(issue, validationStatusFilter, cachedValidations); matchesValidationStatus(issue, validationStatusFilter, cachedValidations);
if (matchesAllFilters) { if (matchesAllFilters) {
matchedIssueNumbers.add(issue.number); matchedIssues.push(issue);
} }
} }
return { return {
matchedIssueNumbers, matchedIssues,
availableLabels, availableLabels,
availableAssignees, availableAssignees,
availableMilestones, availableMilestones,
hasActiveFilter, hasActiveFilter,
matchedCount: matchedIssueNumbers.size, matchedCount: matchedIssues.length,
}; };
}, [ }, [
issues, issues,

View File

@@ -72,8 +72,8 @@ export interface IssuesFilterState {
* Result of applying filters to the issues list * Result of applying filters to the issues list
*/ */
export interface IssuesFilterResult { export interface IssuesFilterResult {
/** Set of issue numbers that match the current filters */ /** Array of GitHubIssue objects that match the current filters */
matchedIssueNumbers: Set<number>; matchedIssues: GitHubIssue[];
/** Available labels from all issues (for filter dropdown population) */ /** Available labels from all issues (for filter dropdown population) */
availableLabels: string[]; availableLabels: string[];
/** Available assignees from all issues (for filter dropdown population) */ /** Available assignees from all issues (for filter dropdown population) */

View File

@@ -2,7 +2,6 @@ export { useAutoMode } from './use-auto-mode';
export { useBoardBackgroundSettings } from './use-board-background-settings'; export { useBoardBackgroundSettings } from './use-board-background-settings';
export { useElectronAgent } from './use-electron-agent'; export { useElectronAgent } from './use-electron-agent';
export { useGuidedPrompts } from './use-guided-prompts'; export { useGuidedPrompts } from './use-guided-prompts';
export { useIssuesFilter } from '@/components/views/github-issues-view/hooks/use-issues-filter';
export { useKeyboardShortcuts } from './use-keyboard-shortcuts'; export { useKeyboardShortcuts } from './use-keyboard-shortcuts';
export { useMessageQueue } from './use-message-queue'; export { useMessageQueue } from './use-message-queue';
export { useOSDetection, type OperatingSystem, type OSDetectionResult } from './use-os-detection'; export { useOSDetection, type OperatingSystem, type OSDetectionResult } from './use-os-detection';