gni commited on
Commit ·
945586b
1
Parent(s): b6037e3
feat: add frontend error notification for rate limiting
Browse files- ui/src/App.tsx +24 -1
ui/src/App.tsx
CHANGED
|
@@ -33,6 +33,7 @@ function App() {
|
|
| 33 |
const [language, setLanguage] = useState('auto');
|
| 34 |
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem('pg-theme') as Theme) || 'premium');
|
| 35 |
const [result, setResult] = useState<RedactResponse | null>(null);
|
|
|
|
| 36 |
const [loading, setLoading] = useState(false);
|
| 37 |
const [apiStatus, setApiStatus] = useState<'checking' | 'online' | 'offline'>('online');
|
| 38 |
const [copied, setCopied] = useState(false);
|
|
@@ -66,10 +67,16 @@ function App() {
|
|
| 66 |
const handleRedact = async () => {
|
| 67 |
if (!text.trim()) return;
|
| 68 |
setLoading(true);
|
|
|
|
| 69 |
try {
|
| 70 |
const response = await axios.post(`${API_URL}/api/redact`, { text, language });
|
| 71 |
setResult(response.data);
|
| 72 |
-
} catch (err: any) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 73 |
finally { setTimeout(() => setLoading(false), 400); }
|
| 74 |
};
|
| 75 |
|
|
@@ -192,6 +199,22 @@ function App() {
|
|
| 192 |
|
| 193 |
<div className="flex-grow md:flex-grow relative overflow-hidden bg-inherit h-[500px] md:h-auto md:min-h-0">
|
| 194 |
{loading && <div className="loading-progress"><div className="loading-progress-bar" /></div>}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 195 |
<textarea
|
| 196 |
className={`w-full h-full p-4 sm:p-10 bg-transparent border-none outline-none text-[15px] sm:text-[16px] leading-[1.8] resize-none font-sans custom-scrollbar ${themeClasses.input}`}
|
| 197 |
placeholder="Enter your document content here..."
|
|
|
|
| 33 |
const [language, setLanguage] = useState('auto');
|
| 34 |
const [theme, setTheme] = useState<Theme>(() => (localStorage.getItem('pg-theme') as Theme) || 'premium');
|
| 35 |
const [result, setResult] = useState<RedactResponse | null>(null);
|
| 36 |
+
const [error, setError] = useState<string | null>(null);
|
| 37 |
const [loading, setLoading] = useState(false);
|
| 38 |
const [apiStatus, setApiStatus] = useState<'checking' | 'online' | 'offline'>('online');
|
| 39 |
const [copied, setCopied] = useState(false);
|
|
|
|
| 67 |
const handleRedact = async () => {
|
| 68 |
if (!text.trim()) return;
|
| 69 |
setLoading(true);
|
| 70 |
+
setError(null);
|
| 71 |
try {
|
| 72 |
const response = await axios.post(`${API_URL}/api/redact`, { text, language });
|
| 73 |
setResult(response.data);
|
| 74 |
+
} catch (err: any) {
|
| 75 |
+
console.error(err);
|
| 76 |
+
const msg = err.response?.data?.detail || 'An unexpected error occurred.';
|
| 77 |
+
setError(typeof msg === 'string' ? msg : 'Analysis failed. Please try again.');
|
| 78 |
+
setTimeout(() => setError(null), 6000);
|
| 79 |
+
}
|
| 80 |
finally { setTimeout(() => setLoading(false), 400); }
|
| 81 |
};
|
| 82 |
|
|
|
|
| 199 |
|
| 200 |
<div className="flex-grow md:flex-grow relative overflow-hidden bg-inherit h-[500px] md:h-auto md:min-h-0">
|
| 201 |
{loading && <div className="loading-progress"><div className="loading-progress-bar" /></div>}
|
| 202 |
+
|
| 203 |
+
{/* Error Alert */}
|
| 204 |
+
{error && (
|
| 205 |
+
<div className="absolute top-4 left-4 right-4 z-[60] animate-in slide-in-from-top-4 duration-300">
|
| 206 |
+
<div className="bg-rose-500 text-white px-4 py-3 rounded-xl shadow-2xl flex items-center justify-between gap-3 border border-rose-400">
|
| 207 |
+
<div className="flex items-center gap-3">
|
| 208 |
+
<Shield className="w-5 h-5 flex-none" />
|
| 209 |
+
<p className="text-[11px] sm:text-xs font-bold leading-tight uppercase tracking-wider">{error}</p>
|
| 210 |
+
</div>
|
| 211 |
+
<button onClick={() => setError(null)} className="p-1 hover:bg-white/20 rounded-lg transition-colors">
|
| 212 |
+
<Trash2 className="w-4 h-4" />
|
| 213 |
+
</button>
|
| 214 |
+
</div>
|
| 215 |
+
</div>
|
| 216 |
+
)}
|
| 217 |
+
|
| 218 |
<textarea
|
| 219 |
className={`w-full h-full p-4 sm:p-10 bg-transparent border-none outline-none text-[15px] sm:text-[16px] leading-[1.8] resize-none font-sans custom-scrollbar ${themeClasses.input}`}
|
| 220 |
placeholder="Enter your document content here..."
|