diff --git a/frontend/components/try/CenterPanel.tsx b/frontend/components/try/CenterPanel.tsx index 14e787c..35fea7b 100644 --- a/frontend/components/try/CenterPanel.tsx +++ b/frontend/components/try/CenterPanel.tsx @@ -56,6 +56,11 @@ export function CenterPanel({ tab, onAnalyze }: CenterPanelProps) { const [cleanResult, setCleanResult] = useState(null); const [piiDetectionResult, setPIIDetectionResult] = useState(null); + + // Strategy selection state for custom anonymization choices + const [selectedStrategies, setSelectedStrategies] = useState< + Record + >({}); const reset = () => { setFileMeta(null); @@ -103,6 +108,20 @@ export function CenterPanel({ tab, onAnalyze }: CenterPanelProps) { try { const result = await detectPII(uploadedFile); setPIIDetectionResult(result); + + // Initialize selected strategies with recommended defaults + const initialStrategies: Record< + string, + { enabled: boolean; strategy: string } + > = {}; + result.risky_features.forEach((feature) => { + initialStrategies[feature.column] = { + enabled: true, + strategy: feature.recommended_strategy, + }; + }); + setSelectedStrategies(initialStrategies); + setProgressLabel("PII detection complete!"); } catch (err: any) { setError(err.message || "PII detection failed"); @@ -122,7 +141,8 @@ export function CenterPanel({ tab, onAnalyze }: CenterPanelProps) { setProgressLabel("Cleaning dataset..."); try { - const result = await cleanDataset(uploadedFile); + // Pass the selected strategies to the API + const result = await cleanDataset(uploadedFile, selectedStrategies); setCleanResult(result); setProgressLabel("Cleaning complete!"); } catch (err: any) { @@ -2821,199 +2841,385 @@ export function CenterPanel({ tab, onAnalyze }: CenterPanelProps) { {/* Risky Features List */} -
- {piiDetectionResult.risky_features.map((feature, idx) => { - const riskColor = - feature.risk_level === "HIGH" - ? "red" - : feature.risk_level === "MEDIUM" - ? "orange" - : feature.risk_level === "LOW" - ? "yellow" - : "gray"; - - const bgColor = - feature.risk_level === "HIGH" - ? "bg-red-50 border-red-300" - : feature.risk_level === "MEDIUM" - ? "bg-orange-50 border-orange-300" - : feature.risk_level === "LOW" - ? "bg-yellow-50 border-yellow-300" - : "bg-gray-50 border-gray-300"; - - return ( -
+ {/* Bulk Selection Controls */} +
+
+ Bulk Actions: +
+
+ + + +
+
+ + {/* Individual Feature Cards */} +
+ {piiDetectionResult.risky_features.map((feature, idx) => { + const riskColor = + feature.risk_level === "HIGH" + ? "red" + : feature.risk_level === "MEDIUM" + ? "orange" + : feature.risk_level === "LOW" + ? "yellow" + : "gray"; + + const bgColor = + feature.risk_level === "HIGH" + ? "bg-red-50 border-red-300" + : feature.risk_level === "MEDIUM" + ? "bg-orange-50 border-orange-300" + : feature.risk_level === "LOW" + ? "bg-yellow-50 border-yellow-300" + : "bg-gray-50 border-gray-300"; + + const isEnabled = + selectedStrategies[feature.column]?.enabled ?? true; + const selectedStrategy = + selectedStrategies[feature.column]?.strategy ?? + feature.recommended_strategy; + + return ( +
+ {/* Header with Checkbox */} +
+
+ { + setSelectedStrategies((prev) => ({ + ...prev, + [feature.column]: { + ...prev[feature.column], + enabled: e.target.checked, + strategy: + prev[feature.column]?.strategy ?? + feature.recommended_strategy, + }, + })); + }} + className="mt-1 w-5 h-5 text-green-600 rounded focus:ring-2 focus:ring-green-500 cursor-pointer" + /> +
+
+ + {feature.risk_level} RISK + + + {feature.column} + +
+
+ + Detected: + {" "} + {feature.entity_type} + + + Confidence: + {" "} + {(feature.confidence * 100).toFixed(1)}% + + + Occurrences: + {" "} + {feature.detection_count} +
+
-
- {/* Explanation */} -
-
- WHY IS THIS RISKY? -
-

- {feature.explanation} -

-
- GDPR Reference:{" "} - {feature.gdpr_article} -
-
- - {/* Sample Values */} - {feature.sample_values.length > 0 && ( + {/* Explanation */}
- SAMPLE VALUES + WHY IS THIS RISKY?
-
- {feature.sample_values.map((val, i) => ( - - {val} - - ))} +

+ {feature.explanation} +

+
+ GDPR Reference:{" "} + {feature.gdpr_article}
- )} - {/* Recommended Strategy */} -
-
-
-
- ✓ RECOMMENDED STRATEGY + {/* Sample Values */} + {feature.sample_values.length > 0 && ( +
+
+ SAMPLE VALUES
-
- {feature.recommended_strategy} -
-
- {feature.strategy_description} -
-
-
- Reversible:{" "} - {feature.reversible ? "Yes" : "No"} -
-
- Use Cases:{" "} - {feature.use_cases.join(", ")} -
+
+ {feature.sample_values.map((val, i) => ( + + {val} + + ))} +
+
+ )} + + {/* Strategy Selection */} +
+
+
+
+ {isEnabled + ? "✓ SELECT ANONYMIZATION STRATEGY" + : "⚠️ STRATEGY DISABLED"} +
+ + + {/* Show selected strategy description */} + {isEnabled && + piiDetectionResult.available_strategies[ + selectedStrategy + ] && ( +
+
+ { + piiDetectionResult + .available_strategies[ + selectedStrategy + ].description + } +
+
+
+ Risk Level:{" "} + + { + piiDetectionResult + .available_strategies[ + selectedStrategy + ].risk_level + } + +
+
+ Reversible:{" "} + {piiDetectionResult + .available_strategies[ + selectedStrategy + ].reversible + ? "Yes" + : "No"} +
+
+
+ Use Cases:{" "} + {piiDetectionResult.available_strategies[ + selectedStrategy + ].use_cases.join(", ")} +
+
+ )}
-
- - {/* Alternative Strategies */} -
- - View Alternative Strategies - -
- {Object.entries( - piiDetectionResult.available_strategies, - ) - .filter( - ([strategy]) => - strategy !== feature.recommended_strategy, - ) - .map(([strategy, details]: [string, any]) => ( -
-
- {strategy} -
-
- {details.description} -
-
- - {details.risk_level} Risk - - -
-
- ))} -
-
-
- ); - })} + ); + })} +
- {/* Apply All Button */} + {/* Apply All Button with Strategy Summary */}
+ {/* Strategy Summary */} +
+
+ 📋 Selected Strategies Summary +
+
+
+
+ Total Features: +
+
+ {piiDetectionResult.risky_features.length} +
+
+
+
+ Enabled: +
+
+ { + Object.values(selectedStrategies).filter( + (s) => s.enabled, + ).length + } +
+
+
+
+ Disabled: +
+
+ { + Object.values(selectedStrategies).filter( + (s) => !s.enabled, + ).length + } +
+
+
+
+
+ Enabled Strategies: +
+
+ {Object.entries(selectedStrategies) + .filter(([_, config]) => config.enabled) + .map(([column, config]) => ( +
+ {column}: {config.strategy} +
+ ))} + {Object.values(selectedStrategies).filter( + (s) => s.enabled, + ).length === 0 && ( +
+ No strategies enabled +
+ )} +
+
+
+ +
+ Note: Only enabled features will be anonymized +
) : (