Skip to content

Commit 7f37848

Browse files
Merge pull request #121 from bg-playground/copilot/fix-eslint-errors-in-suggestion-filters
Fix 11 frontend ESLint errors blocking CI lint job
2 parents bc4b1cc + 08089f8 commit 7f37848

11 files changed

Lines changed: 75 additions & 67 deletions

frontend/src/components/SuggestionFilters.tsx

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,6 @@
11
import React, { useCallback, useEffect, useRef, useState } from 'react';
2-
3-
export const DEFAULT_FILTERS = {
4-
minScore: 0,
5-
maxScore: 1,
6-
algorithm: 'all',
7-
sortBy: 'score',
8-
sortOrder: 'desc',
9-
search: '',
10-
};
11-
12-
export type Filters = typeof DEFAULT_FILTERS;
2+
import { DEFAULT_FILTERS } from '../types/filters';
3+
import type { Filters } from '../types/filters';
134

145
interface SuggestionFiltersProps {
156
filters: Filters;
@@ -19,20 +10,22 @@ interface SuggestionFiltersProps {
1910

2011
export const SuggestionFilters: React.FC<SuggestionFiltersProps> = ({ filters, onFiltersChange, onReset }) => {
2112
const [searchInput, setSearchInput] = useState(filters.search);
13+
const [prevSearch, setPrevSearch] = useState(filters.search);
2214
const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
2315

16+
// Sync searchInput when filters.search is reset externally (e.g. Reset button)
17+
if (prevSearch !== filters.search) {
18+
setPrevSearch(filters.search);
19+
setSearchInput(filters.search);
20+
}
21+
2422
// Clear debounce timer on unmount
2523
useEffect(() => {
2624
return () => {
2725
if (debounceRef.current) clearTimeout(debounceRef.current);
2826
};
2927
}, []);
3028

31-
// Sync searchInput when filters.search is reset externally (e.g. Reset button)
32-
useEffect(() => {
33-
setSearchInput(filters.search);
34-
}, [filters.search]);
35-
3629
const handleSearchChange = useCallback(
3730
(value: string) => {
3831
setSearchInput(value);

frontend/src/components/Toast.tsx

Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,6 @@
1-
import React, { createContext, useContext, useState, useCallback } from 'react';
2-
3-
interface Toast {
4-
id: string;
5-
message: string;
6-
type: 'success' | 'error' | 'info' | 'warning';
7-
}
8-
9-
interface ToastContextValue {
10-
toasts: Toast[];
11-
showToast: (message: string, type?: Toast['type']) => void;
12-
removeToast: (id: string) => void;
13-
}
14-
15-
const ToastContext = createContext<ToastContextValue | undefined>(undefined);
16-
17-
export const useToast = () => {
18-
const context = useContext(ToastContext);
19-
if (!context) {
20-
throw new Error('useToast must be used within a ToastProvider');
21-
}
22-
return context;
23-
};
1+
import React, { useState, useCallback } from 'react';
2+
import { ToastContext } from '../context/ToastContext';
3+
import type { Toast } from '../context/ToastContext';
244

255
export const ToastProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
266
const [toasts, setToasts] = useState<Toast[]>([]);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { createContext, useContext } from 'react';
2+
3+
export interface Toast {
4+
id: string;
5+
message: string;
6+
type: 'success' | 'error' | 'info' | 'warning';
7+
}
8+
9+
export interface ToastContextValue {
10+
toasts: Toast[];
11+
showToast: (message: string, type?: Toast['type']) => void;
12+
removeToast: (id: string) => void;
13+
}
14+
15+
export const ToastContext = createContext<ToastContextValue | undefined>(undefined);
16+
17+
export const useToast = () => {
18+
const context = useContext(ToastContext);
19+
if (!context) {
20+
throw new Error('useToast must be used within a ToastProvider');
21+
}
22+
return context;
23+
};

frontend/src/pages/ManualLinksPage.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import React, { useEffect, useState } from 'react';
1+
import React, { useCallback, useEffect, useState } from 'react';
22
import { linksApi } from '../api/links';
33
import { requirementsApi } from '../api/requirements';
44
import { testCasesApi } from '../api/testCases';
55
import { LinkSource, LinkType } from '../types/api';
66
import type { Link, LinkCreate, Requirement, TestCase } from '../types/api';
77
import { LoadingSpinner } from '../components/LoadingSpinner';
8-
import { useToast } from '../components/Toast';
8+
import { useToast } from '../context/ToastContext';
99

1010
export const ManualLinksPage: React.FC = () => {
1111
const [links, setLinks] = useState<Link[]>([]);
@@ -21,7 +21,7 @@ export const ManualLinksPage: React.FC = () => {
2121
});
2222
const { showToast } = useToast();
2323

24-
const loadData = async () => {
24+
const loadData = useCallback(async () => {
2525
try {
2626
setLoading(true);
2727
const [linksData, reqData, tcData] = await Promise.all([
@@ -38,11 +38,11 @@ export const ManualLinksPage: React.FC = () => {
3838
} finally {
3939
setLoading(false);
4040
}
41-
};
41+
}, [showToast]);
4242

4343
useEffect(() => {
4444
loadData();
45-
}, []);
45+
}, [loadData]);
4646

4747
const handleSubmit = async (e: React.FormEvent) => {
4848
e.preventDefault();
@@ -52,9 +52,10 @@ export const ManualLinksPage: React.FC = () => {
5252
setShowModal(false);
5353
resetForm();
5454
await loadData();
55-
} catch (error: any) {
55+
} catch (error: unknown) {
5656
console.error('Error creating link:', error);
57-
const message = error.response?.data?.detail || 'Failed to create link';
57+
const axiosError = error as { response?: { data?: { detail?: string } } };
58+
const message = axiosError?.response?.data?.detail ?? 'Failed to create link';
5859
showToast(message, 'error');
5960
}
6061
};

frontend/src/pages/MetricsDashboardPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useState } from "react";
22
import traceabilityApi, { type Metrics } from "../api/traceability";
3-
import { useToast } from "../components/Toast";
3+
import { useToast } from "../context/ToastContext";
44
import { LoadingSpinner } from "../components/LoadingSpinner";
55

66
export default function MetricsDashboardPage() {

frontend/src/pages/RequirementsPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { requirementsApi } from '../api/requirements';
33
import { RequirementType, PriorityLevel, RequirementStatus } from '../types/api';
44
import type { Requirement, RequirementCreate, RequirementUpdate } from '../types/api';
55
import { LoadingSpinner } from '../components/LoadingSpinner';
6-
import { useToast } from '../components/Toast';
6+
import { useToast } from '../context/ToastContext';
77

88
export const RequirementsPage: React.FC = () => {
99
const [requirements, setRequirements] = useState<Requirement[]>([]);

frontend/src/pages/SuggestionDashboard.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@ import { testCasesApi } from '../api/testCases';
66
import { SuggestionStatus } from '../types/api';
77
import type { Suggestion, Requirement, TestCase } from '../types/api';
88
import { LoadingSpinner } from '../components/LoadingSpinner';
9-
import { useToast } from '../components/Toast';
9+
import { useToast } from '../context/ToastContext';
1010
import { KeyboardShortcutsHelp } from '../components/KeyboardShortcutsHelp';
11-
import { SuggestionFilters, DEFAULT_FILTERS } from '../components/SuggestionFilters';
12-
import type { Filters } from '../components/SuggestionFilters';
11+
import { SuggestionFilters } from '../components/SuggestionFilters';
12+
import { DEFAULT_FILTERS } from '../types/filters';
13+
import type { Filters } from '../types/filters';
1314
import { SuggestionStats } from '../components/SuggestionStats';
1415
import { SuggestionCard } from '../components/SuggestionCard';
1516
import { SuggestionPreviewModal } from '../components/SuggestionPreviewModal';

frontend/src/pages/TestCasesPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { testCasesApi } from '../api/testCases';
33
import { TestCaseType, PriorityLevel, TestCaseStatus } from '../types/api';
44
import type { TestCase, TestCaseCreate, TestCaseUpdate } from '../types/api';
55
import { LoadingSpinner } from '../components/LoadingSpinner';
6-
import { useToast } from '../components/Toast';
6+
import { useToast } from '../context/ToastContext';
77

88
export const TestCasesPage: React.FC = () => {
99
const [testCases, setTestCases] = useState<TestCase[]>([]);

frontend/src/pages/TraceabilityMatrixPage.tsx

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { useEffect, useState } from "react";
1+
import { useCallback, useEffect, useState } from "react";
22
import traceabilityApi, { type TraceabilityMatrix } from "../api/traceability";
3-
import { useToast } from "../components/Toast";
3+
import { useToast } from "../context/ToastContext";
44
import { LoadingSpinner } from "../components/LoadingSpinner";
55

66
export default function TraceabilityMatrixPage() {
@@ -9,11 +9,7 @@ export default function TraceabilityMatrixPage() {
99
const [exporting, setExporting] = useState(false);
1010
const { showToast } = useToast();
1111

12-
useEffect(() => {
13-
loadMatrix();
14-
}, []);
15-
16-
const loadMatrix = async () => {
12+
const loadMatrix = useCallback(async () => {
1713
try {
1814
setLoading(true);
1915
const data = await traceabilityApi.getMatrix();
@@ -24,7 +20,11 @@ export default function TraceabilityMatrixPage() {
2420
} finally {
2521
setLoading(false);
2622
}
27-
};
23+
}, [showToast]);
24+
25+
useEffect(() => {
26+
loadMatrix();
27+
}, [loadMatrix]);
2828

2929
const handleExport = async (format: "csv" | "json") => {
3030
try {

frontend/src/types/api.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ export interface Requirement {
3535
status: RequirementStatus;
3636
module?: string;
3737
tags?: string[];
38-
custom_metadata?: Record<string, any>;
38+
custom_metadata?: Record<string, unknown>;
3939
source_system?: string;
4040
source_url?: string;
4141
created_by?: string;
@@ -52,7 +52,7 @@ export interface RequirementCreate {
5252
status?: RequirementStatus;
5353
module?: string;
5454
tags?: string[];
55-
custom_metadata?: Record<string, any>;
55+
custom_metadata?: Record<string, unknown>;
5656
source_system?: string;
5757
source_url?: string;
5858
created_by?: string;
@@ -67,7 +67,7 @@ export interface RequirementUpdate {
6767
status?: RequirementStatus;
6868
module?: string;
6969
tags?: string[];
70-
custom_metadata?: Record<string, any>;
70+
custom_metadata?: Record<string, unknown>;
7171
source_system?: string;
7272
source_url?: string;
7373
}
@@ -115,7 +115,7 @@ export interface TestCase {
115115
automated: boolean;
116116
automation_script?: string;
117117
estimated_duration_minutes?: number;
118-
custom_metadata?: Record<string, any>;
118+
custom_metadata?: Record<string, unknown>;
119119
created_by?: string;
120120
version: number;
121121
created_at: string;
@@ -137,7 +137,7 @@ export interface TestCaseCreate {
137137
automated?: boolean;
138138
automation_script?: string;
139139
estimated_duration_minutes?: number;
140-
custom_metadata?: Record<string, any>;
140+
custom_metadata?: Record<string, unknown>;
141141
created_by?: string;
142142
external_id?: string;
143143
}
@@ -157,7 +157,7 @@ export interface TestCaseUpdate {
157157
automated?: boolean;
158158
automation_script?: string;
159159
estimated_duration_minutes?: number;
160-
custom_metadata?: Record<string, any>;
160+
custom_metadata?: Record<string, unknown>;
161161
}
162162

163163
export enum LinkType {
@@ -221,7 +221,7 @@ export interface Suggestion {
221221
similarity_score: number;
222222
suggestion_method: SuggestionMethod;
223223
suggestion_reason?: string;
224-
suggestion_metadata?: Record<string, any>;
224+
suggestion_metadata?: Record<string, unknown>;
225225
status: SuggestionStatus;
226226
created_at: string;
227227
reviewed_at?: string;

0 commit comments

Comments
 (0)