Skip to content

Commit c44196e

Browse files
committed
Normalize bouncers response in select
Move response-shaping logic out of queryFn and into react-query's select. queryFn now returns response.data.data directly, while select handles both array and object formats and returns a typed Bouncer[] (or an empty array) for consistent downstream usage.
1 parent 93b702f commit c44196e

3 files changed

Lines changed: 20 additions & 35 deletions

File tree

web/src/components/Footer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ export default function Footer() {
33
<footer className="border-t border-border bg-card px-6 py-3">
44
<div className="flex items-center justify-between text-sm text-muted-foreground">
55
<div className="flex items-center gap-4">
6-
<span>CrowdSec Manager Beta-v0.0.6 | Powered by CrowdSec(Project is not affiliated with CrowdSec)</span>
6+
<span>CrowdSec Manager | Powered by CrowdSec(Project is not affiliated with CrowdSec)</span>
77
</div>
88
<div className="flex items-center gap-4">
99
<span>&copy; {new Date().getFullYear()} HHF Technology</span>

web/src/layouts/Sidebar.tsx

Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ import {
1919
Target,
2020
Bell,
2121
HeartPulse,
22-
Moon,
23-
Sun,
2422
TerminalSquare,
2523
ShieldCheck,
2624
Package,
@@ -29,10 +27,8 @@ import {
2927
ScanSearch,
3028
AppWindow,
3129
} from 'lucide-react'
32-
import { Button } from '@/components/ui/button'
3330
import { ScrollArea } from '@/components/ui/scroll-area'
3431
import { Separator } from '@/components/ui/separator'
35-
import { useTheme } from '@/contexts/ThemeContext'
3632
import {
3733
Tooltip,
3834
TooltipContent,
@@ -109,17 +105,12 @@ export const navigation = [
109105

110106
export default function Sidebar({ isCollapsed, setIsCollapsed: _setIsCollapsed, onNavigate }: SidebarProps) {
111107
const location = useLocation()
112-
const { theme, setTheme } = useTheme()
113108

114109
// Persist collapsed state to localStorage
115110
useEffect(() => {
116111
localStorage.setItem('sidebar-collapsed', String(isCollapsed))
117112
}, [isCollapsed])
118113

119-
const toggleTheme = () => {
120-
setTheme(theme === "dark" ? "light" : "dark")
121-
}
122-
123114
return (
124115
<div
125116
className={cn(
@@ -209,30 +200,21 @@ export default function Sidebar({ isCollapsed, setIsCollapsed: _setIsCollapsed,
209200
</div>
210201
</ScrollArea>
211202

212-
{/* Footer with Theme Toggle and Copyright */}
203+
{/* Footer with Copyright */}
213204
<div className="px-3 py-2 shrink-0">
214205
<Separator className="mb-3 bg-sidebar-border" />
215206
<div className={cn("flex items-center", isCollapsed ? "justify-center" : "justify-between gap-2")}>
216-
<Button
217-
variant="ghost"
218-
size={isCollapsed ? "icon" : "sm"}
219-
onClick={toggleTheme}
220-
className={cn(
221-
"text-muted-foreground hover:bg-sidebar-accent/50 hover:text-sidebar-foreground shrink-0",
222-
isCollapsed ? "h-8 w-8" : "gap-2 px-2"
223-
)}
224-
>
225-
{theme === "dark" ? (
226-
<Sun className="h-4 w-4 shrink-0" />
227-
) : (
228-
<Moon className="h-4 w-4 shrink-0" />
229-
)}
230-
{!isCollapsed && <span className="truncate">Toggle Theme</span>}
231-
</Button>
232207
{!isCollapsed && (
233-
<p className="text-[10px] text-muted-foreground text-right leading-tight shrink-0">
234-
&copy; {new Date().getFullYear()} HHF Technology<br />
235-
Powered by CrowdSec
208+
<p className="text-[10px] text-muted-foreground text-left leading-tight shrink-0">
209+
&copy; {new Date().getFullYear()} Crowdsec Manager by {' '}
210+
<a
211+
href="https://forum.hhf.technology"
212+
target="_blank"
213+
rel="noopener noreferrer"
214+
className="text-muted-foreground hover:text-foreground transition-colors"
215+
>
216+
HHF Technology
217+
</a>
236218
</p>
237219
)}
238220
</div>

web/src/pages/Bouncers.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,14 @@ export default function Bouncers() {
5252
queryKey: ['bouncers'],
5353
queryFn: async () => {
5454
const response = await api.crowdsec.getBouncers()
55-
// Handle both array and object response formats
56-
const data = response.data.data
57-
if (Array.isArray(data)) return data
58-
if (data && Array.isArray((data as { bouncers: Bouncer[] }).bouncers)) return (data as { bouncers: Bouncer[] }).bouncers
59-
return []
55+
return response.data.data
56+
},
57+
select: (data) => {
58+
if (Array.isArray(data)) return data as Bouncer[]
59+
if (data && Array.isArray((data as { bouncers: Bouncer[] }).bouncers)) {
60+
return (data as { bouncers: Bouncer[] }).bouncers
61+
}
62+
return [] as Bouncer[]
6063
},
6164
})
6265

0 commit comments

Comments
 (0)