feat: Add indicator version filtering to analytics dashboard
- Add version dropdown selector (v9, v8, v6, v5, all) to frontend - Update backend API to accept ?version= query parameter - Add version filter to all 5 broken SQL queries using Prisma parameterized queries - Update Data Collection Status to use selected version instead of hardcoded v8 - Add version context to all recommendations - Add URL encoding for version parameter (security best practice) - Validate version parameter against whitelist (SQL injection protection) Co-authored-by: mindesbunister <32161838+mindesbunister@users.noreply.github.com>
This commit is contained in:
@@ -11,15 +11,25 @@ interface AnalysisResult {
|
||||
action?: string
|
||||
}
|
||||
|
||||
// Available indicator versions for filtering
|
||||
const INDICATOR_VERSIONS = [
|
||||
{ value: 'v9', label: 'v9 - Current Production' },
|
||||
{ value: 'v8', label: 'v8 - Previous Version' },
|
||||
{ value: 'v6', label: 'v6 - Legacy' },
|
||||
{ value: 'v5', label: 'v5 - Legacy' },
|
||||
{ value: 'all', label: 'All Versions (Historical)' },
|
||||
]
|
||||
|
||||
export default function OptimizationPage() {
|
||||
const [analyses, setAnalyses] = useState<AnalysisResult[]>([])
|
||||
const [loading, setLoading] = useState(true)
|
||||
const [lastRefresh, setLastRefresh] = useState<Date | null>(null)
|
||||
const [selectedVersion, setSelectedVersion] = useState<string>('v9') // Default to current production
|
||||
|
||||
const loadAnalyses = async () => {
|
||||
setLoading(true)
|
||||
try {
|
||||
const response = await fetch('/api/optimization/analyze')
|
||||
const response = await fetch(`/api/optimization/analyze?version=${encodeURIComponent(selectedVersion)}`)
|
||||
const data = await response.json()
|
||||
setAnalyses(data.analyses)
|
||||
setLastRefresh(new Date())
|
||||
@@ -32,7 +42,8 @@ export default function OptimizationPage() {
|
||||
|
||||
useEffect(() => {
|
||||
loadAnalyses()
|
||||
}, [])
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [selectedVersion]) // Reload when version changes
|
||||
|
||||
return (
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900 text-white p-8">
|
||||
@@ -60,8 +71,25 @@ export default function OptimizationPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Refresh Button */}
|
||||
<div className="mb-6">
|
||||
{/* Version Selector and Refresh Button */}
|
||||
<div className="mb-6 flex items-center gap-4 flex-wrap">
|
||||
<div className="flex items-center gap-3">
|
||||
<label htmlFor="version-select" className="text-sm font-medium text-slate-300">
|
||||
Indicator Version:
|
||||
</label>
|
||||
<select
|
||||
id="version-select"
|
||||
value={selectedVersion}
|
||||
onChange={(e) => setSelectedVersion(e.target.value)}
|
||||
className="px-4 py-2 bg-slate-700 rounded-lg border border-slate-600 text-white focus:border-blue-500 focus:outline-none"
|
||||
>
|
||||
{INDICATOR_VERSIONS.map((v) => (
|
||||
<option key={v.value} value={v.value}>
|
||||
{v.label}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
<button
|
||||
onClick={loadAnalyses}
|
||||
disabled={loading}
|
||||
@@ -69,6 +97,11 @@ export default function OptimizationPage() {
|
||||
>
|
||||
{loading ? '🔄 Analyzing...' : '🔄 Refresh All Analyses'}
|
||||
</button>
|
||||
{selectedVersion !== 'all' && (
|
||||
<span className="text-sm text-green-400 font-medium">
|
||||
✓ Filtering by {selectedVersion.toUpperCase()}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Loading State */}
|
||||
|
||||
Reference in New Issue
Block a user